ClassCastException when using TreeMap

Viewed 153

I have a TreeMap<Integer, TreeMap<int[][], Integer>> jungle. When I try to execute the statements

TreeMap<int[][], Integer> tempMap = new TreeMap();
int[][] matrix = {{1}};
tempMap.put(matrix, 4);

this last line gives me the

java.lang.ClassCastException: [[I cannot be cast to java.base/java.lang.Comparable at java.base/java.util.TreeMap.compare

exception. Am I not allowed to use an int[][] as a key in a treeMap?

2 Answers

The purpose of a TreeMap is to have an ordered collection

A Red-Black tree based NavigableMap implementation. The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.

You must pass a Comparator that deals with int[][]; here an example with one that sorted based on the full sum of the array

class Custom2DArrayComparator implements Comparator<int[][]> {

    private static int sum(int[][] v) {
        return Arrays.stream(v).map(arr -> Arrays.stream(arr).sum())
                               .mapToInt(Integer::intValue).sum();
    }

    @Override
    public int compare(int[][] o1, int[][] o2) {
        return Integer.compare(sum(o1), sum(o2));
    }
}

Use

public static void main(String[] args) {
    TreeMap<int[][], Integer> tempMap = new TreeMap<>(new Custom2DArrayComparator());
    int[][] matrix = {{1}};
    tempMap.put(matrix, 4);
}

You can use the anonymous class to avoid creating a one outside

public static void main(String[] args) {
    TreeMap<int[][], Integer> tempMap = new TreeMap<>(new Comparator<>() {
        @Override
        public int compare(int[][] o1, int[][] o2) {
            return Integer.compare(sum(o1), sum(o2));
        }

        int sum(int[][] v) {
            return Arrays.stream(v).map(arr -> Arrays.stream(arr).sum())
                .mapToInt(Integer::intValue).sum();
        }
    });
    int[][] matrix = {{1}};
    tempMap.put(matrix, 4);
}

You'll need to implement your own logic in order for your key to be Comparable, as Johannes' comment points out. You could create a class that implements Comparator and pass it as argument at the initialization of the TreeMap.

Note that the default/overriden compare method would also be valid, as arrays are just Objects.

You could even implement all the logics for non-comparable Object keys you wish to insert in different Maps in a single class:

public class NonCompObjectKeyComparator implements Comparator<Object> 
{         
    @Override
    public int compare(Object o1, Object o2) 
    {
       if (o1 instanceof int[][])
       {
         //((int[][])o1),((int[][])o2)//
       }
       else if (o1 instanceof String[])
       {
         //((String[])o1),((String[])o2)//
       }
       else if (o1 instanceof <OtherNonComparableObjType>)
       {
         //...
       }
       //...          
       return 0;
    }
}

And then you got your überComparator there:

Comparator<Object> maCompa = new NonCompObjectKeyComparator();

TreeMap<int[][], Integer> tempMap   = new TreeMap(maCompa);
TreeMap<String[], String> sArrayMap = new TreeMap(maCompa);

int[][] matrix = {{1}};
tempMap.put(matrix, 4);

String[] sKey = {"a"};
sArrayMap.put(sKey, "anotherWierdMap");

In order to create an specific int[][] comparator, just:

public class CustomKeyComparator implements Comparator<int[][]> {    

    public int compare(int[][] a1, int[][] a2) {
        //your logic here
        return 0;
    }
}

and

TreeMap<int[][], Integer> tempMap = new TreeMap(new CustomKeyComparator());
int[][] matrix = {{1}};
tempMap.put(matrix, 4);

Related