user243872
user243872

Reputation: 361

Loop diagonally through two dimensional array

I wrote the following code to walk half the diagonals of an array:

String[][] b = [a,b,c]
               [d,e,f]
               [g,h,i];  

public void LoopDiag()
   for (int i = b.length - 1; i > 0; i--) {
       String temp = "";
       for (int j = 0, x = i; x <= b.length - 1; j++, x++) {
          temp = temp+b[x][j];
       }
       System.out.println(temp)
   }


   for (int i = 0; i <= b.length - 1; i++) {
        String temp = "";
        for (int j = 0, y = i; y <= b.length - 1; j++, y++) {
        temp = temp+b[j][y];
        }
        System.out.println(temp);
   }
}

Right now it prints the diagonals i.e current output:

g dh aei bf c

How do I make it print the other half diagonals i.e required output:

a db gec hf i 

Upvotes: 24

Views: 96441

Answers (12)

Nicolai
Nicolai

Reputation: 5797

Initialize array only for test purpose:

int dim = 5;
char ch = 'A';
String[][] array = new String[dim][];
for( int i = 0 ; i < dim ; i++ ) {
    array[i] = new String[dim];
    for( int j = 0 ; j < dim ; j++, ch++ ) {
        array[i][j] = "" + ch;
    }
}

Output our matrix:

for( int i = 0 ; i < dim ; i++ ) {
    for( int j = 0 ; j < dim ; j++, ch++ ) {
        System.out.print( array[i][j] + " " );
    }
    System.out.println();
}
System.out.println( "============================" );

Solution

Element indexes from diagonals have one rule - their sum is constant on one diagonal:

Variant 1

Use two loops to extract all diagonals.

First loop extracts top half of diagonals:

for( int k = 0 ; k < dim ; k++ ) {
    for( int j = 0 ; j <= k ; j++ ) {
        int i = k - j;
        System.out.print( array[i][j] + " " );
    }
    System.out.println();
}

Second loop iterates on bottom half of diagonals:

for( int k = dim - 2 ; k >= 0 ; k-- ) {
    for( int j = 0 ; j <= k ; j++ ) {
        int i = k - j;
        System.out.print( array[dim - j - 1][dim - i - 1] + " " );
    }
    System.out.println();
}

Variant 2

Use one loop to extract all diagonals, but there are extra iterations and one additional check:

for( int k = 0 ; k < dim * 2 ; k++ ) {
    for( int j = 0 ; j <= k ; j++ ) {
        int i = k - j;
        if( i < dim && j < dim ) {
            System.out.print( array[i][j] + " " );
        }
    }
    System.out.println();
}

The output:

A B C D E 
F G H I J 
K L M N O 
P Q R S T 
U V W X Y 
============================
A 
F B 
K G C 
P L H D 
U Q M I E 
V R N J 
W S O 
X T 
Y 

Update

There are questions about rectangular matrix (height != width) in comments. Here is solution for rectangular matrix:

The rule remains the same: Sum of element indexes from the same diagonal is constant

The minimum sum of indexes is 0 (for first element in matrix with indexes [0;0])

The maximum sum of indexes is width + height - 2 (for last element in matrix with indexes [height-1; with-1])

Initialize rectangular matrix only for test purpose:

int WIDTH = 7;
int HEIGHT = 3;
char ch = 'A';
String[][] array = new String[HEIGHT][];
for( int i = 0 ; i < HEIGHT ; i++ ) {
    array[i] = new String[WIDTH];
    for( int j = 0 ; j < WIDTH ; j++, ch++ ) {
        array[i][j] = "" + ch;
    }
}

Print our rectangular matrix:

for( int i = 0 ; i < HEIGHT ; i++ ) {
    for( int j = 0 ; j < WIDTH ; j++, ch++ ) {
        System.out.print( array[i][j] + " " );
    }
    System.out.println();
}
System.out.println( "============================" );

Solution

for( int k = 0 ; k <= WIDTH + HEIGHT - 2; k++ ) {
    for( int j = 0 ; j <= k ; j++ ) {
        int i = k - j;
        if( i < HEIGHT && j < WIDTH ) {
            System.out.print( array[i][j] + " " );
        }
    }
    System.out.println();
}

Output:

A B C D E F G 
H I J K L M N 
O P Q R S T U 
============================
A 
H B 
O I C 
P J D 
Q K E 
R L F 
S M G 
T N 
U 

Upvotes: 35

Surya P
Surya P

Reputation: 11

Type 1: We can solve this using python very easily

Code:

r,c=map(int,input().split())
mat=[[str(ch) for ch in input().split()]for _ in range(r)]
for i in range(r*c-2):
    lis=[]
    for j in range(r):
        for k in range(c):
            if k+j==i:
                lis.append(mat[j][k])
    print(*lis[::-1])

Output:

5 5
a b c d e
f g h i j
k l m n o
p q r s t
u v w x y

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

Upvotes: 1

Aditya
Aditya

Reputation: 1344

Here is the code:

public void loopDiag(String [][] b) {

        boolean isPrinted  = false;
        for (int i = 0 ; i < b.length ; i++) {
            String temp="";
            int x=i;
            for(int j = 0 ; j < b.length ; j++) {
                int y = j;
                while (x >= 0 && y < b.length) {
                    isPrinted = false;
                    temp+=b[x--][y++];                  
                }
                if(!isPrinted) {
                    System.out.println(temp);
                    isPrinted = true;
                }
            }
        }
    }

Upvotes: 1

Apurv Jaiswal
Apurv Jaiswal

Reputation: 11

    String ar[][]={{"a","b","c"},{"d","e","f"},{"g","h","i"}};
    int size1=ar.length-1, size2=ar.length;

    for(int i=0; i<ar.length; i++)
    {   
        String a="";        
        for(int j=0, x=ar.length-1-i; j<ar.length-i; j++, x--)
        {
            if((j+x)==size1)
            a=a+ar[x][j];
        }
        size1--;

        System.out.println(a);
        a="";
        for(int j=i+1, x=ar.length-1; j<ar.length; j++, x--)
        {
            if((j+x)==size2)
            a=a+ar[x][j];
        }
        System.out.println(a);
        size2++;
    }

OUTPUT

gec hf db i a

Upvotes: 1

brahmananda Kar
brahmananda Kar

Reputation: 59

This is very intuitive way to print diagonal matrix in while loop .

generalize the problem as whole rather than two part and optimized in terms of space complexity .

package algorithm;

public class printDiagonaly
{
    public static void main(String[] args)
    {
        int[][] a = new int[][]{{1, 2, 3, 4, 5},
                {6, 7, 8, 9, 10},
                {11, 12, 13, 14, 15},
                {16, 17, 18, 19, 20}};

        int lr = 0;
        int lc = -1;
        int fr = -1;
        int fc = 0;
        int row = a.length - 1;
        int col = a[0].length - 1;

        while (lc < col || fc < col || fr < row || lr < row)
        {
            if (fr < row)
            {
                fr++;
            }
            else
            {
                fc++;
            }

            if (lc < col)
            {
                lc++;
            }
            else
            {
                lr++;
            }

            int tfr = fr;
            int tlr = lr;
            int tlc = lc;
            int tfc = fc;

            while (tfr >= tlr && tfc <= tlc)
            {

                System.out.print(a[tfr][tfc] + " ");
                tfr--;
                tfc++;
            }
            System.out.println("\n");
        }
    }
}

Upvotes: 2

Shubham Vadhera
Shubham Vadhera

Reputation: 138

This is how:

int [][]mat = { {1,2,3},
                {4,5,6},
                {7,8,9},
};

int N=3;

for (int s=0; s<N; s++) {
    for (int i=s; i>-1; i--) {
        System.out.print(mat[i][s-i] + " ");
    }
    System.out.println();
}

for (int s=1; s<N; s++) {
    for (int i=N-1; i>=s; i--) {
        System.out.print(mat[i][s+N-1-i] + " ");
    }
    System.out.println();
}

The first loop prints the diagonals beginning from first column, the second loop prints the remaining diagonals (beginning from bottom row).

Output:

1 
4 2 
7 5 3 
8 6 
9 

Upvotes: 1

Big O
Big O

Reputation: 417

Solutions would be much easier if we break it down into 2 sub-problems:

  1. Figure out the start of each diagonal.
  2. Given the starting indices of a diagonal, print the diagonal.

    public void printMatrixDiagonals(int[][] matrix) {
    
        int c = 0;
        int count = matrix.length + matrix[0].length -1;
        int i = 0, j = 0;
        //There can be at most  m + n -1 diagonals to be printed
        while (c < count) {
            //Start printing diagonals from i and j
            printDiagonal(i, j, matrix);
            if (i < matrix.length -1) {
                //We increment row index until we reach the max number of rows
                i++;
            } else if (j < matrix[0].length - 1) {
                //We are at maximum index of row; so its time to increment col index
                //We increment column index until we reach the max number of columns
                j++;
            }
            c++;
        }
    }
    

Print Diagonal: Notice that every time we start printing each diagonal, the index of row should be decremented and the index of column should be incremented. So given the starting indices of each diagonal, we can print the diagonal as follows:

private void printDiagonal(int i, int j, int[][] m) {
    while (i >=0 && j< m[0].length ) {
        System.out.print(m[i][j] + " ");
        i--;
        j++;
    }
    System.out.println("");
}

Upvotes: 4

Twin
Twin

Reputation: 45

This is the same as what leoflower posted here. I've just changed the variable names for better understanding.

level = denotes the current level of the diagonal that is being printed. Ex:- level = 2 denotes diagonal elements with indices (0,2),(1,1),(2,0)

currDiagRowIndex = denotes row index of the current diagonal being printed

currDiagColIndex = denotes columnn index of the current diagonal being printed

void printMatrixDiagonal(int matrix[][], int endRowIndex, int endColIndex){
    for(int level = 0; level < endColIndex; level++){
        for(int currDiagRowIndex = 0, currDiagColIndex = level; currDiagRowIndex < endRowIndex && currDiagColIndex >= 0 ; currDiagRowIndex++, currDiagColIndex--){
            System.out.print(matrix[currDiagRowIndex][currDiagColIndex] + "  ");
        }
        System.out.println();
    }

    for(int level = 1; level < endRowIndex; level++){
        for(int currDiagRowIndex = level, currDiagColIndex = endColIndex-1; currDiagRowIndex < endRowIndex && currDiagColIndex >= 0; currDiagRowIndex++, currDiagColIndex--){
            System.out.print(matrix[currDiagRowIndex][currDiagColIndex]+ "  ");
        }
        System.out.println();
    }
}

Input:

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

Output:

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

Upvotes: -1

leoflower
leoflower

Reputation: 575

As Alex mentioned here, you need to look into indices in the loop. The following is how I approached this problem.

Input:         
a b c    ----- (0,0) (0,1) (0,2)
d e f    ----- (1,0) (1,1) (1,2)
g h i    ----- (2,0) (2,1) (2,2)

Output:
a        ----- (0,0)
b d      ----- (0,1) (1,0)
c e g    ----- (0,2) (1,1) (2,0)
f h      ----- (1,2) (2,1)
i        ----- (2,2)

public class PrintDiagonal{

    public static void printDR(String[][] matrix, int rows, int cols){
        for(int c=0; c < cols; c++){
            for(int i=0, j=c; i< rows && j>=0;i++,j--){
                System.out.print(matrix[i][j] +" ");
             }
             System.out.println();
        }

        for(int r =1; r < rows; r++){
            for(int i =r, j= cols -1; i<rows && j>=0; i++,j--){
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }
    public static void main(String[] args){
        String[][] matrix ={
            {"a","b","c"},
            {"d","e","f"},
            {"g","h","i"}
        };

        int rows = matrix.length;
        int columns = matrix[0].length; 
        printDR(matrix ,rows, columns);
    }
}

Upvotes: 1

Greg Whittier
Greg Whittier

Reputation: 3185

This works for non-square arrays. It's simple to understand, but calls min() and max() once per diagonal.

int ndiags = width +  height - 1;
System.out.println("---");
for (int diag = 0; diag < ndiags; diag++) {
    int row_stop = Math.max(0,  diag -  width + 1);
    int row_start = Math.min(diag, height - 1);
    for (int row = row_start; row >= row_stop; row--) {
        // on a given diagonal row + col = constant "diag"
        // diag labels the diagonal number
        int col = diag - row;
        System.out.println(col + "," + row);
        relax(col, row);
    }
    System.out.println("---");
}

Here's output for width=3, height=3

---
0,0
---
0,1
1,0
---
0,2
1,1
2,0
---
1,2
2,1
---
2,2
---

width=3, height=2

---
0,0
---
0,1
1,0
---
1,1
2,0
---
2,1
---

width = 2, height = 3

---
0,0
---
0,1
1,0
---
0,2
1,1
---
1,2
---

Upvotes: 5

AtlasMeh-ed
AtlasMeh-ed

Reputation: 477

I wrote the following code. The key is to exhaust all of the diagonals that start at the top and then move onto the diagonals that start on the sides. I included a method that combines the two angles to traverse diagonals Northwest - Southeast and Northeast - Southwest and stand alone methods for traversing the respective angles.

public static void main(String[] args){
    int[][] m = {{1,2,3},{4,5,6},{7,8,9},{10,11,12}};
    printDiagonals(m, DiagonalDirection.NEtoSW, new DiagonalVisitor() {     
        public void visit(int x, int y, int[][] m) {
            System.out.println(m[x][y]);
        }
    });
}

public enum DiagonalDirection{
    NWToSE,
    NEtoSW
}

private static abstract class DiagonalVisitor{
    public abstract void visit(int x, int y, int[][] m);
}

public static void printDiagonals(int[][] m, DiagonalDirection d, DiagonalVisitor visitor){

    int xStart = d==DiagonalDirection.NEtoSW ? 0 : m.length-1;
    int yStart = 1;


    while(true){
        int xLoop, yLoop;
        if(xStart>=0 && xStart<m.length){
            xLoop = xStart;
            yLoop = 0;
            xStart++;
        }else if(yStart<m[0].length){
            xLoop = d==DiagonalDirection.NEtoSW ? m.length-1 : 0;
            yLoop = yStart;
            yStart++;
        }else
            break;

        for(;(xLoop<m.length && xLoop>=0)&&yLoop<m[0].length; xLoop=d==DiagonalDirection.NEtoSW ? xLoop-1 : xLoop+1, yLoop++){
            visitor.visit(xLoop, yLoop, m);
        }

    }

}

public static void printDiagonalsNEtoSW(int[][] m, DiagonalVisitor visitor){

    int xStart = 0;
    int yStart = 1;


    while(true){
        int xLoop, yLoop;
        if(xStart<m.length){
            xLoop = xStart;
            yLoop = 0;
            xStart++;
        }else if(yStart<m[0].length){
            xLoop = m.length-1;
            yLoop = yStart;
            yStart++;
        }else
            break;

        for(;xLoop>=0 && yLoop<m[0].length; xLoop--, yLoop++){
            visitor.visit(xLoop, yLoop, m);
        }


    }
}

public static void printDiagonalsNWtoSE(int[][] m, DiagonalVisitor visitor){

    int xStart = m.length-1;
    int yStart = 1;


    while(true){
        int xLoop, yLoop;
        if(xStart>=0){
            xLoop = xStart;
            yLoop = 0;
            xStart--;
        }else if(yStart<m[0].length){
            xLoop = 0;
            yLoop = yStart;
            yStart++;
        }else
            break;

        for(;xLoop<m.length && yLoop<m[0].length; xLoop++, yLoop++){
            visitor.visit(xLoop, yLoop, m);
        }       
    }
}

Upvotes: 6

alex
alex

Reputation: 5684

Just help yourself, have a look at the indices you need to loop through:

#1 (0,0)               -> a
#2 (1,0)  (0,1)        -> bd
#3 (2,0)  (1,1)  (0,2) -> gec
#4 (2,1)  (1,2)        -> hf
#5 (2,2)               -> i

Look at the change of the indices in each iteration and create your algorithm. Not so difficult, so do your homework yourself ;)

Upvotes: 4

Related Questions