Wilson
Wilson

Reputation: 77

How to compare a bi-dimensional array

I have this bi-dimensional array:

int[][] matrix = new int[][]  {
        { 4, 4, 4, 4, 4}, 
        { 4, 3, 4, 3, 4},
        { 4, 3, 4, 3, 4},
        { 4, 3, 4, 3, 3},
        { 1, 1, 1, 3, 3},
        { 4, 4, 4, 3, 3},
        { 4, 5, 4, 3, 3},
        { 4, 4, 4, 3, 3}}; 

First I want to compare the first element with the second, then the second with the third and so on, row by row.

Then I want to do the same thing on a column by column basis, comparing the element [0,0] with the element [1,0], then comparing [1,0] with [2,0] and so on, for each column.

That is an easy thing to be done using for() loops:

for (int r=0; r<A.length;r++) {
    for (int c=0; c<A[r].length;c++){
        if (if (matrix[r][c]==matrix[r][c+1])){
            // do somet
        }
    }
}

But what I need is to do the same using Java 8 functional programming with lambdas and streams iteration.

Upvotes: 1

Views: 124

Answers (1)

Alex Pakka
Alex Pakka

Reputation: 9706

You question is a bit unclear to provide universally applicable code. But probably has enough to set you on the right path.

Let's assume you just wanted to find adjacent duplicates:

    //reference code
    for (int[] row : matrix) {
        for (int c = 0; c < row.length - 1; c++) {
            if (row[c] == row[c + 1]) {
                System.out.print(row[c]+" ");
            }
        }
    }
    //prints 4 4 4 4 3 1 1 3 4 4 3 3 4 4 3 

Let's also assume your matrix will never contain -1. Then you could do

    //simple accumulator with a side effect of print out
    IntBinaryOperator accumulator = (acc, x) -> {
        if (acc == x) System.out.print(x + " ");
        return x;
    };

    //also prints 4 4 4 4 3 1 1 3 4 4 3 3 4 4 3 
    Arrays.stream(matrix).forEach(arr -> Arrays.stream(arr).reduce(-1, accumulator));

reduce(-1, accumulator) would work on any int array to find same numbers next to each other. Accumulator function keeps previous number in acc and compares with incoming one. Of course, identity as -1 is cheating, canonical way would be to use Arrays.stream(arr).boxed()... and use null as identity (and it still would be cheating, but will allow all ints in your matrix).

Here is another version:

//prints 4 4 4 4 4 4 4 3 1 1 3 4 4 3 3 4 4 3 
Arrays.stream(matrix).flatMapToInt(Arrays::stream).reduce(-1, accumulator);

This time no forEach(), but since it flattens the matrix, it will compare last element of a row with first element of the next row - could be a bug or a feature.

Finally, accumulator with a side effect of printing stuff is no good in functional programming. Ideally you should collect() a list of duplicates and return it - since your question is so vague, I will trust you can write it yourself with the information above.

You could so some other interesting things with matrices and streams and duplicates, e.g. this will take much more coding than two embedded loops:

 Map<Integer,Long> m = Arrays.stream(matrix)
            .parallel()
            .flatMapToInt(Arrays::stream)
            .boxed()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
 System.out.println(m); //prints occurences of each int: {1=3, 3=15, 4=21, 5=1}

In the end, streams are no silver bullet, just a nice help from time to time. Some languages have better syntax and more powerful constructs to adapt functional style, but Java is liked for something else.

Upvotes: 2

Related Questions