Printing string in rows and column pattern Java

Viewed 3452

i'm just created a java project to print string that is given in rows and column just like matrix. Here's the output that i just made:

h e l l o 
_ w o r l 
d _ i t s 
_ b e a u 
t i f u l 

Is it possible to show the output like a spiral pattern like this?

h e l l o
_ b e a _
s u l u w
t f i t o
i _ d l r

For the clarification how this spiral matrix created:

Spriral matrix pattern

Here's my current code:

String str = "hello world its beautiful";
    double length = Math.sqrt(str.length());
    int x = (int) length;

    for (int i = 0, len = str.length(); i < len; i++) {
        System.out.print(str.charAt(i) + " ");
        if (i % x == x - 1) {
            System.out.println();
        }
    }

I'm trying to make the same pattern like that, but it's never be. Let me know that you can help me with this. I appreciate for every answer that you gave, thank you.

7 Answers

Basically, you move through the string from start to end, but treat the stringbuffer as an array. You#ll also need to to keep track of your direction (dx,dy) and where your bounds are.

The following code will produce:

hello
beau 
 l.tw
sufio
i dlr

given the input "hello world is beautiful"

public class Main {

    public static void main(String[] args) {
        String text ="hello world is beautiful";
        int len = text.length();
        double sideLength = Math.sqrt( len );
        int width = 0;
        int height = 0;

        // check if it's a square
        if ( sideLength > (int) sideLength) {
            // nope... it#s a rectangle
            width = (int) sideLength +1;
            height = (int) Math.ceil((double)len / (double)width);
        } else {
            // square
            width = (int) sideLength;
            height = (int) sideLength;
        }

        // create a buffer for the spiral
        StringBuffer buf = new StringBuffer( width * height );
        buf.setLength( width * height );
        // clear it.
        for (int a=0; a < buf.length(); a++ ) {
            buf.setCharAt(a, '.');
        }
        

        int dstX = 0;
        int dstY = 0;
        int curWidth =  width;
        int curHeight = height;
        int startX = 0;
        int startY = 0;
        int dx = 1;
        int dy = 0;
        // go through the string, char by char
        for (int srcPos =0; srcPos < len; srcPos++) {
            buf.setCharAt( dstX + dstY * width, text.charAt( srcPos ));

            // move cursor
            dstX += dx;
            dstY += dy;

            // check for bounds
            if ( dstX == curWidth-1 && dx > 0) {
                // end of line while going right, need to go down
                dx = 0;
                dy = 1;
                // also, reduce width
                curWidth--;
                startY++;
            } else if (dstY == curHeight-1 && dy > 0) {
                // end of column while going down, need to go left
                dx = -1;
                dy = 0;

                // also, reduce height
                curHeight--;
            } else if (dstX == startX && dx < 0) {
                // hit left border while going left, need to go up
                dx = 0;
                dy = -1;
                // also, increase startX
                startX++;
            } else if (dstY == startY && dy < 0) {
                // hit top border, while going up, need to go right
                dx = 1;
                dy = 0;
                // also, increase startY
                startY++;
            }
            
        }


        // display string
        for (int line = 0; line < height; line++) {
            System.out.println( buf.substring( line* width, line*width +width) );
        }
    }
}

spiralMatrix(int s) returns s x s spiral matrix.

static int[][] spiralMatrix(int s) {
    int[][] a = new int[s][s];
    int n = 0;
    for (int b = s - 1, c = 0, x = 0, y = 0, dx = 0, dy = 1; b > 0; b -= 2, x = y = ++c)
        for (int j = 0, t = 0; j < 4; ++j, t = dx, dx = dy, dy = -t)
            for (int i = 0; i < b; ++i, x += dx, y += dy, ++n)
                a[x][y] = n;
    if (s % 2 == 1)
        a[s / 2][s / 2] = n;
    return a;
}

test

for (int s = 0; s < 6; ++s) {
    int[][] a = spiralMatrix(s);
    System.out.println("s=" + s);
    for (int[] row : a)
        System.out.println(Arrays.toString(row));
    System.out.println();
}

result

s=0

s=1
[0]

s=2
[0, 1]
[3, 2]

s=3
[0, 1, 2]
[7, 8, 3]
[6, 5, 4]

s=4
[0, 1, 2, 3]
[11, 12, 13, 4]
[10, 15, 14, 5]
[9, 8, 7, 6]

s=5
[0, 1, 2, 3, 4]
[15, 16, 17, 18, 5]
[14, 23, 24, 19, 6]
[13, 22, 21, 20, 7]
[12, 11, 10, 9, 8]

And you can do it with this method.

String str = "hello world its beautiful";
int[][] spiral = spiralMatrix(5);
int length = str.length();
for (int x = 0, h = spiral.length, w = spiral[0].length; x < h; ++x) {
    for (int y = 0; y < w; ++y) {
        int p = spiral[x][y];
        System.out.print((p < length ? str.charAt(p) : " ") + " " );
    }
    System.out.println();
}

result

h e l l o 
  b e a   
s u l u w 
t f i t o 
i   d l r 

you could try to make the spiral algorithm first and try to find the value of its each index in the matrix so that later you could map every index of your string into the specific index in the spiral array matrix.

for example:

Input: n = 5
Output:   1   2   3   4   5
          16  17  18  19  6
          15  24  25  20  7
          14  23  22  21  8
          13  12  11  10  9
Aligned Output:  1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9

the algorithm can be found here or here.

now you know all the index of each position to make the letters aligned in a spiral way, what you have to do is map each letter of your string to be print according to the number of the spiral matrix sequentially.

print string 1.
print string 2.
print string 3.   
print string 4.
print string 5.
print string 16.
print string 17.
print string 18.
print string 19.
print string 6.
print string 15.
cont...

Probably I'll add my answer too, idea is to flatten a two dimensional array to 1d and use the 1D array and transform it to a 2D spiral array. Hope it helps.

Code:

class Test {

    static String[][] spiralPrint(int m, int n, String[] a) {
        String[][] output = new String[m][n];
        int count = 0;
        int i, k = 0, l = 0;
        while (k < m && l < n) {
            for (i = l; i < n; ++i) {
                output[k][i] = a[count++];
            }
            k++;

            for (i = k; i < m; ++i) {
                output[i][n - 1] = a[count++];
            }
            n--;

            if (k < m) {
                for (i = n - 1; i >= l; --i) {
                    output[m - 1][i] = a[count++];
                }
                m--;
            }

            if (l < n) {
                for (i = m - 1; i >= k; --i) {
                    output[i][l] = a[count++];
                }
                l++;
            }
        }
        return output;
    }

    private static String[] flattenArray(String[][] input, int m, int n) {
        String[] output = new String[m * n];
        int k = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                output[k++] = input[i][j];
            }
        }
        return output;
    }

    public static void main(String[] args) {

        String[][] input = {
                {"h", "e", "l", "l", "o"},
                {"_", "w", "o", "r", "l"},
                {"d", "_", "i", "t", "s"},
                {"_", "b", "e", "a", "u"},
                {"t", "i", "f", "u", "l"}};

        int m = 5;
        int n = 5;

        String[] flattenArray = flattenArray(input, m, n);
        String[][] spiralArray = spiralPrint(m, n, flattenArray);

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print(spiralArray[i][j] + " ");
            }
            System.out.println();
        }

    }
}

Output:
h e l l o 
_ b e a _ 
s u l u w 
t f i t o 
i _ d l r 

Note: Indeed that I followed this Spiral transform to 1D, but it is not straight forward, I have re-modified to fit to the problem.

I think that the best way to implement this is the following:

  1. create an instruction object (Dictionary.java) which controls the fill-in process of the matrix
  2. fill in the matrix with data (Spiral.java)
  3. then show the matrix

With this approach, you can change the pattern easily, without changing the rest of the code because the pattern generator works detached from the rest of the code.

This is how the basic Dictionary class may look like:

public abstract class Dictionary {

    protected int matrixSize;
    protected String[] dictionary;

    public Dictionary(int matrixSize) {
        this.matrixSize = matrixSize;
        dictionary = new String[matrixSize * matrixSize];
    }

    public abstract String[] createPattern();

    public void showPattern() {
        Arrays.stream(dictionary).forEach(System.out::println);
    }
}

For each pattern, you need to implement the createPattern() method differently. For example, a frame pattern implementation can be something like this:

public class FrameDictionary extends Dictionary {

    protected int dictionaryIndex = 0;
    protected int startX, endX;
    protected int startY, endY;

    public FrameDictionary(int matrixSize) {
        super(matrixSize);
        startX = -1;
        endX = matrixSize - 1;
        startY = 0;
        endY = matrixSize - 1;
    }

    @Override
    public String[] createPattern() {
        while (dictionaryIndex < matrixSize) {
            pattern1();
            pattern2();
        }
        return dictionary;
    }

    /**
     * pattern 1
     * direction: left -> right then top -> bottom
     */
    protected void pattern1() {
        startX++;
        for (int i = startX; i <= endX; i++) {
            dictionary[dictionaryIndex] = i + ":" + startY;
            dictionaryIndex++;
        }

        startY++;
        for (int i = startY; i <= endY; i++) {
            dictionary[dictionaryIndex] = endX + ":" + i;
            dictionaryIndex++;
        }
    }

    /**
     * pattern 2
     * direction: right -> left then bottom -> top
     */
    protected void pattern2() {
        endX--;
        for (int i = endX; i >= startX; i--) {
            dictionary[dictionaryIndex] = i + ":" + endY;
            dictionaryIndex++;
        }

        endY--;
        for (int i = endY; i >= startY; i--) {
            dictionary[dictionaryIndex] = startX + ":" + i;
            dictionaryIndex++;
        }
    }
}

Output:

a b c d e f
t         g
s         h
r         i
q         j
p o n m l k

You can draw the pattern what you need with the following implementation of the createPattern() method:

public class ClockWiseDictionary extends FrameDictionary {

    public ClockWiseDictionary(int matrixSize) {
        super(matrixSize);
    }

    @Override
    public String[] createPattern() {
        int pixelsInMatrix = matrixSize * matrixSize;
        while (dictionaryIndex < pixelsInMatrix) {
            pattern1();
            pattern2();
        }
        return dictionary;
    }
}

Output:

a b c d e f
t u v w x g
s 6 7 8 y h
r 5 0 9 z i
q 4 3 2 1 j
p o n m l k

Or just for fun, a "snake" pattern implementation:

public class SnakeDictionary extends Dictionary {

    private int dictionaryIndex = 0;
    private int startY = 0;

    public SnakeDictionary(int matrixSize) {
        super(matrixSize);
    }

    @Override
    public String[] createPattern() {
        int pixelsInMatrix = matrixSize * matrixSize;
        while (dictionaryIndex < pixelsInMatrix) {
            pattern1();
            if (dictionaryIndex < pixelsInMatrix) {
                pattern2();
            }
        }

        return dictionary;
    }

    public void pattern1() {
        for (int i = 0; i < matrixSize; i++) {
            dictionary[dictionaryIndex] = i + ":" + startY;
            dictionaryIndex++;
        }
        startY++;
    }

    public void pattern2() {
        for (int i = matrixSize - 1; i >= 0; i--) {
            dictionary[dictionaryIndex] = i + ":" + startY;
            dictionaryIndex++;
        }
        startY++;
    }
}

Output:

a b c d e f
l k j i h g
m n o p q r
x w v u t s
y z 1 2 3 4
0 9 8 7 6 5

This is how the main method looks like:

public static void main(String[] args) {
    String sentence = "abcdefghijklmnopqrstuvwxyz1234567890";
    String[][] spiral = new String[MATRIX_SIZE][MATRIX_SIZE];

    // Dictionary dictionary = new FrameDictionary(MATRIX_SIZE);
    Dictionary dictionary = new ClockWiseDictionary(MATRIX_SIZE);
    // Dictionary dictionary = new SnakeDictionary(MATRIX_SIZE);

    String[] pattern = dictionary.createPattern();
    //dictionary.showPattern();

    Spiral.fill(sentence, pattern, spiral);
    Spiral.show(spiral);
}

You can check/download the complete source code from GitHub.

Hope that it helps you.

Here's a one with a recursive approach,

I am traversing the matrix in right -> down -> left -> up fashion on the boundaries

Then change the size and do the same for inner boundaries,

Matrix M would be a spiral matrix then of character indices Create spiral matrix C for characters by traversing matrix M.

int m = 5;
int n = 5;
int limit = m * n;
int[][] M = new int[m][n];
public void spiral(int[][] M, int row, int col, int c, int start, int m, int n) {
    if (c > limit | row >= m | col >= n)
        return;

    if (M[row][col] == 0)
        M[row][col] = c;

    if (row == start) // go right
        spiral(M, row, col + 1, c + 1, start, m, n);

    if (col == n - 1) // go down
        spiral(M, row + 1, col, c + 1, start, m, n);

    if (row == m - 1 && col > start) // go left
        spiral(M, row, col - 1, c + 1, start, m, n);

    if (col == start && row >= start) // go up
        spiral(M, row - 1, col, c + 1, start, m, n);
    
};
spiral(M, 0, 0, 1, 0, m, n);

for (int i = m - 1, x = 1, j = n - 1; i >= m - 2 && j >= n - 2; i--, j--, x++)
    spiral(M, x, x, M[x][x - 1] + 1, x, i, j);

This would give you spiral Matrix M Output:

1   2   3   4   5   
16  17  18  19  6   
15  24  25  20  7   
14  23  22  21  8   
13  12  11  10  9

Then create a spiral matrix for characters using matrix M

String string = "hello_world_its_beautiful";
char[][] C = new char[size][size];
for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++)
        C[i][j] = string.charAt(M[i][j] - 1);
}

Output:

h   e   l   l   o   
_   b   e   a   _   
s   u   l   u   w   
t   f   i   t   o   
i   _   d   l   r

When can't go straight turn left to walk, this is the theory used in this solution

int dr[] = {0, 1, 0, -1};
int dc[] = {1, 0, -1, 0};

this is used for always move pattern. And curr & curc represent current position and curm represent current move pattern.

  public int[][] solve(int r, int c, String s) {
    int m[][] = new int[5][5];
    int curr = 0, curc = 0;
    
    for (int pos = 0, curm = 0; pos < r*c; pos++) {
      m[curr][curc] = (int) s.charAt(pos);
      if (curr + dr[curm] < 0 || curr + dr[curm] >= r || curc + dc[curm] < 0 || curc + dc[curm] >= c
          || m[curr + dr[curm]][curc + dc[curm]] != 0)
        curm = (curm + 1) % 4;
      curr = curr + dr[curm];
      curc = curc + dc[curm];
    }
    return m;
  }

Then you can print this way

for (int i = 0; i < r; i++) {
  for (int j = 0; j < c; j++) {
    System.out.printf("%c ", m[i][j]);
  }
  System.out.println("");
}
Related