Home > database >  I try to compare two Collections of int arrays and I've got results which origin I don't u
I try to compare two Collections of int arrays and I've got results which origin I don't u

Time:01-15

I am solving this kata on Codewars: https://www.codewars.com/kata/635fc0497dadea0030cb7936 this is my code:

    public static void main(String[] args) {
        int[][] ms;

        ms = new int[][] {{1, 2, 3, 4},
                {3, 1, 4, 2},
                {4, 3, 2, 1},
                {2, 4, 1, 3}};
        System.out.println(count_different_matrices(ms));
    }


    private static final Set<int[]> registeredM = new HashSet<>();
    static public int count_different_matrices(int[][] matrices) {
        Arrays.stream(matrices).forEach(m -> {
        if(unwrapPossibleMatrices(m).stream().noneMatch(registeredM::contains)) {
            registeredM.add(m);

        }});
        registeredM.forEach(e -> System.out.println(Arrays.toString(e)));
        return registeredM.size();
    }

    static private List<int[]> unwrapPossibleMatrices(int[] m) {
        return Arrays.asList(new int[][]{
                m,
                {m[2], m[0], m[3], m[1]},
                {m[3], m[2], m[1], m[0]},
                {m[1], m[3], m[0], m[2]}
        });
    }

Output received in the console:

[1, 2, 3, 4]
[2, 4, 1, 3]
[4, 3, 2, 1]
[3, 1, 4, 2]
4

I expected output of only [1, 2, 3, 4], My train of thought was that contains() should invoke a.equals(b) where a and b in this example is of type int[] and when they will be compared by equals - it will check if length and elements in the arrays match. Instead what happened (I think) was that address of the object was checked - thus, giving different results for arrays with the same elements. My question is the following: how to modify this code to check actual elements passed in arrays?

CodePudding user response:

Ok, I've changed my solution as @Pshemo pointed out (thank you :)

public static void main(String[] args) {
        int[][] ms;

        ms = new int[][] {{1, 2, 3, 4},
                {3, 1, 4, 2},
                {4, 3, 2, 1},
                {2, 4, 1, 3}};
        System.out.println(count_different_matrices(ms));
    }
    
    private static final Set<Row> registeredM = new HashSet<>();
    static public int count_different_matrices(int[][] matrices) {
        registeredM.clear();
        Arrays.stream(matrices).forEach(m -> {
        if(unwrapPossibleMatrices(m).stream().noneMatch(registeredM::contains)) {
            registeredM.add(new Row(m));

        }});
        registeredM.forEach(e -> System.out.println(Arrays.toString(e.row())));
        return registeredM.size();
    }

    private static List<Row> unwrapPossibleMatrices(int[] m) {
        return Arrays.asList(
                new Row(m), 
                new Row(new int[]{m[2], m[0], m[3], m[1]}), 
                new Row(new int[]{m[3], m[2], m[1], m[0]}), 
                new Row(new int[]{m[1], m[3], m[0], m[2]})
        );
    }

    record Row(int[] row) {
        @Override
        public int hashCode() {
            return Arrays.hashCode(row);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Row row1 = (Row) o;
            return Arrays.equals(row, row1.row);
        }
    }

CodePudding user response:

You can write a Comparator that compares two int arrays.

Here's a code example.

import java.util.Comparator;
import java.util.Arrays;

public class CompareArrays {
    
    Comparator<int[]> comparator = new Comparator<>() {
        public int compare(int[] a1, int[] a2) {
            if (a1.length != a2.length)
                return a1.length - a2.length;
            for (int i = 0; i < a1.length; i  ) {
                if (a1[i] != a2[i])
                    return a1[i] - a2[i];
            }
            return 0;
        }
    };

    public void test(int[] a, int[] b) {
        System.out.println("Array1: "   Arrays.stream(a).boxed().toList());
        System.out.println("Array2: "   Arrays.stream(b).boxed().toList());
        System.out.println(comparator.compare(a, b) == 0 ? "Array1 == Array2" : "Array1 != Array2");
    }

    public static void main(String[] args) {
        CompareArrays program = new CompareArrays();
        
        int[] a = {1, 2, 3, 4};
        int[] b = {1, 2, 3, 4};
        int[] c = {1, 2, 3};
        int[] d = {4, 3, 2, 1};
        int[] e = {1, 2, 3, 4, 5};
        int[] f = {1, 2, 4, 3};
        
        program.test(a, b);
        System.out.println();
        
        program.test(a, c);
        System.out.println();
        
        program.test(a, d);
        System.out.println();
        
        program.test(a, e);
        System.out.println();
        
        program.test(a, f);
    }
}

Here's the output after we compile and run.

% javac CompareArrays.java
% java CompareArrays
Array1: [1, 2, 3, 4]
Array2: [1, 2, 3, 4]
Array1 == Array2

Array1: [1, 2, 3, 4]
Array2: [1, 2, 3]
Array1 != Array2

Array1: [1, 2, 3, 4]
Array2: [4, 3, 2, 1]
Array1 != Array2

Array1: [1, 2, 3, 4]
Array2: [1, 2, 3, 4, 5]
Array1 != Array2

Array1: [1, 2, 3, 4]
Array2: [1, 2, 4, 3]
Array1 != Array2

This is one way of doing it. There are other ways.

As you pointed out, the == operator compares the memory addresses of two objects. So if you create two int arrays {1, 2, 3, 4}, they will have different memory addresses, even though both arrays contain the same numbers.

In addition, you can also use the Arrays.equals method.

I just discovered the Arrays.equals and the Arrays.toString methods.

Here is a code example:

import java.util.Arrays;

public class ArraysTest {

    public void run() {
        int[] a = {1, 2, 3, 4};
        int[] b = {1, 2, 3, 4};
        int[] c = {1, 2, 3};
        int[] d = {4, 3, 2, 1};
        int[] e = {1, 2, 3, 4, 5};
        int[] f = {1, 2, 4, 3};
        
        test(a, b);
        System.out.println();
        
        test(a, c);
        System.out.println();
        
        test(a, d);
        System.out.println();
        
        test(a, e);
        System.out.println();
        
        test(a, f);
    }

    public void test(int[] a, int[] b) {
        System.out.println("Array1: "   Arrays.toString(a));
        System.out.println("Array2: "   Arrays.toString(b));
        System.out.println(Arrays.equals(a, b) ? "Array1 == Array2" : "Array1 != Array2");
    }

    public static void main(String[] args) {
        ArraysTest program = new ArraysTest();
        program.run();
    }
}

Here is the output after we compile and run the program. (With later versions of Java we can do this in one step.)

% java ArraysTest.java
Array1: [1, 2, 3, 4]
Array2: [1, 2, 3, 4]
Array1 == Array2

Array1: [1, 2, 3, 4]
Array2: [1, 2, 3]
Array1 != Array2

Array1: [1, 2, 3, 4]
Array2: [4, 3, 2, 1]
Array1 != Array2

Array1: [1, 2, 3, 4]
Array2: [1, 2, 3, 4, 5]
Array1 != Array2

Array1: [1, 2, 3, 4]
Array2: [1, 2, 4, 3]
Array1 != Array2

So you can see that the Arrays.equals(int[], int[]) and the Arrays.toString(int[]) methods are very useful.

The java.util.Arrays class gives us an efficient way of comparing two int arrays (as well as any two primitive arrays).

  •  Tags:  
  • java
  • Related