0
Map<Integer[], Integer> map = new TreeMap<Integer[], Integer>();

I am trying to make a map with two ints in an array as the key and a different int as the value. The arrays will all be unique. However, I keep getting a java.lang.classcastexception error. any advice?

4
  • 4
    TreeMap needs its keys to be Comparable. Or you need to provide a Comparator. The error message of the exception should tell you that. Have you read it? Have you read the javadoc of TreeMap? Commented Apr 2, 2016 at 14:40
  • 1
    Or use HashMap, which does not require Comparable keys. Note that an array will be considered equal only to itself, not to other arrays with the same content. Commented Apr 2, 2016 at 14:56
  • 1
    Write your own object class to use as the key. That way, your object class can implement Comparable. Commented Apr 2, 2016 at 15:08
  • thanks guys. switched to hash map! works perfect. Commented Apr 4, 2016 at 8:20

3 Answers 3

1

UPDATE: As Thomas mentioned, you can pass a custom Comparator to a TreeMap. So your original code can be work with a little modification:

Map<Integer[], Integer> map = new TreeMap<Integer[], Integer>(new IntegerWordComparator());

In this case, IntegerWordComparator will be something similar to IntegerWord (see below), but as an implementation of the Comparator interface:

public class IntegerWordComparator implements Comparator<Integer[]> {

    @Override
    public int compare(Integer[] iw1, Integer[] iw2) {
        int commonLength = Math.min(iw1.length, iw2.length);
        for (int i = 0; i < commonLength; i++) {
            if (iw1[i] > iw2[i]) {
                return 1;
            } else if (iw1[i] < iw2[i]) {
                return -1;
            }
        }
        if (iw1.length > iw2.length) {
            return 1;
        } else if (iw1.length < iw2.length) {
            return -1;
        } else {
            return 0;
        }
    }

}

Original answer

Use List instead of array, and HashMap instead of TreeMap:

Map<List<Integer>, Integer> map = new HashMap<List<Integer>, Integer>();

// add three items two of which are the same
map.put(Arrays.asList(new Integer[]{1, 2, 3}), 1);
map.put(Arrays.asList(new Integer[]{3, 4, 7}), 2);
map.put(Arrays.asList(new Integer[]{1, 2, 3}), 4);

// print the size
System.out.println(map.size()); // 2

If you want to ignore the order, then use Set as key.

If you really want to use TreeMap and you want to compare your arrays lexicographically, then you can write your own class and use it as a key. Here is an example:

public class IntegerWord implements Comparable<IntegerWord> {

    protected final Integer[] integers;

    public IntegerWord(Integer... integers) {
        this.integers = integers;
    }

    @Override
    public int compareTo(IntegerWord other) {
        int commonLength = Math.min(integers.length, other.integers.length);
        for (int i = 0; i < commonLength; i++) {
            if (integers[i] > other.integers[i]) {
                return 1;
            } else if (integers[i] < other.integers[i]) {
                return -1;
            }
        }
        if (integers.length > other.integers.length) {
            return 1;
        } else if (integers.length < other.integers.length) {
            return -1;
        } else {
            return 0;
        }
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof IntegerWord) {
            return (compareTo((IntegerWord)other) == 0);
        } else {
            return false;
        }
    }

    @Override
    public String toString() {
        return Arrays.asList(integers).toString();
    }

}

Usage:

Map<IntegerWord, Integer> map = new TreeMap<IntegerWord, Integer>();
map.put(new IntegerWord(2, 5), 11);
map.put(new IntegerWord(1, 2, 3), 22);
map.put(new IntegerWord(1, 2, 3, 4), 33);
map.put(new IntegerWord(1, 2, 3), 44); // 1, 2, 3 again!
map.put(new IntegerWord(3, 9, 3, 4), 55);
map.put(new IntegerWord(0, 1), 66);
map.put(new IntegerWord(), 77); // will be the first!
System.out.println(map);
Sign up to request clarification or add additional context in comments.

1 Comment

No need to write your own array wrapper: you can pass a Comparator to a TreeMap.
1

Array doesnt implement equals() and hashCode(), so you if you use array as key, you can get value back only with exact same array.

Integer[] key1 = {1, 2, 3};
Integer[] key2 = {1, 2, 3};
System.out.println(key1.equals(key2)); //false
System.out.println(key1.hashCode() == key2.hashCode()); //false

Map<Integer[], String> map = new HashMap<>();
map.put(key1, "value");
System.out.println(map.get(key1)); //value
System.out.println(map.get(key2)); //null

Better to create wrapper like this:

class IntArrayKey {
    Integer[] array;

    public IntArrayKey(Integer... array) {
        this.array = array;
    }

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

    @Override
    public int hashCode() {
        return Arrays.hashCode(array);
    }
}

P.S. For using with TreeMap you can implement Comparable

Comments

0

Here's a working example, using HashMap rather than TreeMap.

import java.util.HashMap;
import java.util.Map;
public class Test {
  public static void main(String[] args) {
    Map<Integer[], Integer> map = new HashMap<Integer[], Integer>();
    Integer[] array1 = {1, 2, 3};
    Integer[] array2 = {4, 5, 6};

    map.put(array1, 42);
    map.put(array2,  -1000);
    System.out.println("array1: "+map.get(array1));
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.