Map with two-dimensional key in java

32,612

Solution 1

You should use Map<Pair<K1,K2>, V>

  1. It will only contain one map, instead of N+1 maps

  2. Key construction will be obvious (creation of the Pair)

  3. Nobody will get confused as to the meaning of the Map as its programmer facing API won't have changed.

  4. Dwell time in the data structure would be shorter, which is good if you find you need to synchronize it later.

Solution 2

If you're willing to bring in a new library (which I recommend), take a look at Table in Guava. This essentially does exactly what you're looking for, also possibly adding some functionality where you may want all of the entries that match one of your two keys.

interface Table<R,C,V>

A collection that associates an ordered pair of keys, called a row key and a column key, with a single value. A table may be sparse, with only a small fraction of row key / column key pairs possessing a corresponding value.

Solution 3

While I also am on board with what you proposed (a pair of values to use as the key), you could also consider making a wrapper which can hold/match both keys. This might get somewhat confusing since you would need to override the equals and hashCode methods and make that work, but it could be a straightforward way of indicating to the next person using your code that the key must be of a special type.

Searching a little bit, I found this post which may be of use to you. In particular, out of the Apache Commons Collection, MultiKeyMap. I've never used this before, but it looks like a decent solution and may be worth exploring.

Solution 4

I'd recommend going for the second option

Map<Pair<K1,K2>,V>

The first one will generate more overload when retrieving data, and even more when inserting/removing data from the Map. Every time that you put a new Value V, you'll need to check if the Map for K1 exists, if not create it and put it inside the main Map, and then put the value with K2.

If you want to have an interface as you're exposing initially wrap your Map<Pair<K1,K2>,V> with your own "DoubleKeyMap".

(And don't forget to properly implement the methods hash and equals in the Pair class!!)

Solution 5

I would opt for the Map<Pair<K1,K2>, V> solution, because:

  • it directly expresses what you want to do
  • is potentially faster because it uses fewer indirections
  • simplifies the client code (the code that uses the Map afterwards
Share:
32,612

Related videos on Youtube

EclipseQuestion
Author by

EclipseQuestion

Updated on July 09, 2022

Comments

  • EclipseQuestion
    EclipseQuestion almost 2 years

    I want a map indexed by two keys (a map in which you put AND retrieve values using two keys) in Java. Just to be clear, I'm looking for the following behavior:

    map.put(key1, key2, value); 
    map.get(key1, key2); // returns value
    map.get(key2, key1); // returns null
    map.get(key1, key1); // returns null
    

    What's the best way to to it? More specifically, should I use:

    • Map<K1,Map<K2,V>>

    • Map<Pair<K1,K2>, V>

    • Other?

    (where K1,K2,V are the types of first key, second key and value respectively)

    • Adrian Mouat
      Adrian Mouat about 13 years
      Can't you just have one key made up of two values?
    • JAB
      JAB about 13 years
      @Adrian: Isn't that what Map<Pair<K1,K2>, V> would do? There's technically only one key, but it consists of two values.
    • EclipseQuestion
      EclipseQuestion about 13 years
      @Adrian Yes, that was what I meant with the second choice
  • EclipseQuestion
    EclipseQuestion about 13 years
    I'm using 'apache commons' lib. Does anyone know if the 'Pair' class will work? (I mean, if it implements hashCode and equals correctly FOR THIS CASE?)
  • Edwin Buck
    Edwin Buck about 13 years
    Hashes need not be perfect, a good way is to implement your own pair. The hashcode() method can just return a.hashCode() xor b.hashCode().
  • Marcelo
    Marcelo about 13 years
    Yes, and you can use the HashBasedTable<R,C,V> implementation guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/‌​…
  • Pedro Borges
    Pedro Borges over 10 years
    But doesn't that just alloc memory for a pair object EVERY time we search for something in the doubleMap? I mean, it's cleaner and all, but what if we're talking a big map with static data, isn't this solution badly engineered memory wise?
  • Edwin Buck
    Edwin Buck over 10 years
    If you are worried about allocating each time you search, it doesn't really matter what kind of Map you use because the Map isn't really the core issue. You would probably want a Factory to generate the Key backed to a store of unique keys, such that two requests to generate two keys return the same object twice. It's independent of the Map of pair issue, and a Map of Maps is likely to take more storage anyway, considering the hash array (1 vs 1*M, in a M*N example) and bucket lists they both will have to maintain.
  • Henno Vermeulen
    Henno Vermeulen about 9 years
    Interestingly, this uses the Map<K1,Map<K2,V>> approach internally.