0

Is it possible to create a map where the key is a Collection (any sort of collection)?

If I try it on most common collections I'm told the collection can't be cast to comparable.

I've been trying to write a compareTo function for a custom collection, but I am struggling.

Either I need to write the compareTo, or I need to find a premade Map that accepts collections/Collection accepted by Maps.

How can I use a collection as a key on a map? I've looked over Stack overflow and I've googled this problem several times, but I've never found a solid solution!


The reason I want to do this is that I've written a 'shuffle' simulation in Java that mimic card shuffling. I want to be able to count up the number of times a specific hand (modeled as a collection) comes up. It would look something like this:

   H4,C3,D2: 8  
   H9,D6,S11: 10  
   ......
4
  • 1
    Why do you want to use a Collection as key on the first place? The whole concept behind the Map is Immutable keys, and Collections directly violate this concept.
    – Rohit Jain
    Commented Jun 19, 2013 at 21:40
  • That would not be a good idea, unless the collections are read-only, they are likely to change, and as a result changing the behavior of their equals and hashCode and most probably giving results very difficult to predict when it comes to checking if a key already exists or while retrieving a key in the map. Commented Jun 19, 2013 at 21:42
  • You could use ArrayList's toString method to use the String as a key, or you could use you custom formatter to create a string for you, every time you append to the String you will need to remove the old string's entry. Commented Jun 20, 2013 at 1:37
  • @user962029 I'm certain i tried that before changing my Card and Deck class but now I've changed it I've not tried it without writing my compareTo method...which I've been struggling with. Commented Jun 20, 2013 at 6:32

2 Answers 2

10

Is it possible to create a map where the key is a Collection (any sort of collection)?

Yes it is possible, but definitely not recommended. If your collection changes, it is likely that its hashcode will also change and that can lead to surprising behaviour.

See Map's javadoc:

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.


If I try it on most common collections I'm told the collection can't be cast to comparable.

The key does not need to be comparable, unless you use a sorted map, i.e. TreeMap. Use a simple HashMap and you won't have the issue.


Following your edit, I would create a new immutable Hand class:

class Hand implements Comparable<Hand> {
    private final List<Card> cards;
    Hand(Card c1, Card c2, Card c3) {
        cards = Collections.unmodifiableList(Arrays.asList(c1, c2, c3));
    }
    //getters, no setters
    //implement compareTo
}

and implement compareTo if you want to use it in a TreeSet<Hand, Integer> and sort by hand strength for example.

5
  • Agree that care must be taken to ensure the key doesn't change while being used as a key. Commented Jun 19, 2013 at 21:42
  • Can this concern be alleviated by using an unmodifiable collection as a key? Commented Jun 19, 2013 at 21:43
  • @tieTYT You only need to make sure you don't modify the key. An unmodifiable collection would enforce that.
    – assylias
    Commented Jun 19, 2013 at 21:44
  • 7
    @assylias Technically it would need to be unmodifiable and a copy. If you use just unmodifiableCollection(coll) you can still modify the underlying collection. :P Commented Jun 19, 2013 at 21:46
  • 1
    In the last edit, I think it would be extremely wise to also implement equals and hashCode, possibly by simply returning the equals and hashCode of the cards field... Commented Jun 19, 2013 at 22:12
2

Yes, you can use any collection as a key. If you want a SortedMap like TreeMap you have to provide a Comparator to determine the order. However if you use any kind of HashMap you don't need.

Map<List<Integer>, String> map = new HashMap<>();
map.put(Arrays.asList(1,2,3), "one to three");
map.put(Arrays.asList(7,8,9), "seven eat nine");
System.out.println(map);

prints

{[1, 2, 3]=one to three, [7, 8, 9]=seven eat nine}

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.