Search code examples
javaarraysjava-8equalsdeepequals

How do I check if two simple 2D arrays have the same 1D arrays? (order and repetitions doesn't matter)


My main objective is to return if all elements, int[ ], of a 2D Array ,int[ ][ ], are present in another 2D Array.

I already tried to use Arrays.deepEquals() but in this case, the order of the elements would matter and that's not the purpose.

  • Int[ ][ ] arrays wouldn't be longer than 15, for example.
  • Int[ ][ ] arrays have always the same length.
  • Int[ ][ ] arrays order doesn't matter, but Int[ ] arrays does.
  • Int[ ] arrays would always be a pair.

Expected:

int[][] array1 = {{1, 2}, {2, 2}, {0, 1}, {3,4}} // Main Array

int[][] array2 = {{0, 1}, {2, 2}, {3,4} {1, 2}}} // Expected: true

int[][] array3 = {{6, 3}, {1, 2}, {7,4} {0, 1}}} // Expected: false
  

This is my solution/try:

// Check if an int[] array (element) belongs to an int[][] array.

public static boolean inVector(int[][] 2dArray, int[] 1dArray) {

    for (int i = 0; i < 2dArray.length; i++) {
        for (int j = 0; j < 2dArray[i].length; j++) {

            if (1dArray[0] == 2dArray[i][0] && 1dArray[1] == 2dArray[i][1]) {
                return true;
            }
        }
    }

    return false;
}


// Check if all int[] arrays of an int[][] belong to another int[][] array.

// This is not working properly

public boolean allBelongs() {

  boolean belongs = false;

  for (int i = 0; i < array1.length; i++) {
     
     if (inVector(array1, array2()[i])) {
        belongs = true;
     }
     
     else {
        belongs = false;
     }
  }

    return belongs;
}

EDIT: I solved the problem reversing the logic of the solution. Posted own answer.


Solution

  • You can use IntBuffer which can wrap an int[] array and provide the equals and hashCode implementations reflecting the array’s content.

    public static boolean sameSubArrays(int[][] array1, int[][] array2) {
        if(array1 == array2) return true;
        HashSet<IntBuffer> set = new HashSet<>();
        for(int[] a: array1) set.add(IntBuffer.wrap(a));
        for(int[] a: array2) if(!set.contains(IntBuffer.wrap(a))) return false;
        return true;
    }
    

    This is simple and runs in linear time, hence, can cope with large arrays. It has the expected result for your test case.

    int[][] array1 = {{1, 2}, {2, 2}, {0, 1}, {3,4}};
    int[][] array2 = {{0, 1}, {2, 2}, {3, 4}, {1, 2}};
    System.out.println(sameSubArrays(array1, array2)); // true
    

    But it does not consider duplicates. If the number of occurrences must match for sub arrays with the same contents, you have to expand the solution to use a map to count the occurrences.

    public static boolean sameSubArrays(int[][] array1, int[][] array2) {
        if(array1 == array2) return true;
        if(array1.length != array2.length) return false;
        HashMap<IntBuffer, Integer> map = new HashMap<>();
        for(int[] a: array1) map.merge(IntBuffer.wrap(a), 1, Integer::sum);
        for(int[] a: array2)
            if(map.merge(IntBuffer.wrap(a), -1, Integer::sum) < 0) return false;
        return true;
    }
    

    Since your example has no duplicates, it still has the same result.