2

I'm reviewing the capabilities of Googles Guava API and I ran into a data structure that I haven't seen used in my 'real world programming' experience, namely, the BiMap. Is the only benefit of this construct the ability to quickly retrieve a key, for a given value? Are there any problems where the solution is best expressed using a BiMap?

Amir Afghani
  • 37,814
  • 16
  • 84
  • 124

2 Answers2

9

Any time you want to be able to do a reverse lookup without having to populate two maps. For instance a phone directory where you would like to lookup the phone number by name, but would also like to do a reverse lookup to get the name from the number.

digitaljoel
  • 26,265
  • 15
  • 89
  • 115
  • How can this be done without two maps? Surely the BiMap must use two Maps and just hide this fact? – Amir Afghani Mar 09 '13 at 17:44
  • 2
    Yeah, it probably does use two maps, but YOU don't have to populate two maps and manage all that. – digitaljoel Mar 09 '13 at 17:45
  • 2
    @digitaljoel: Not probably, it does. See [the source](https://code.google.com/r/baggiogamp-guava/source/browse/guava/src/com/google/common/collect/AbstractBiMap.java?r=4fbef9f220a86423f6ebc131c06bac5c3bb5e731) – jlordo Mar 09 '13 at 17:48
  • 10
    @jlordo, @AmirAfghani: That's a clone of an old version of Guava. The current implementation of `HashBiMap` [does no such thing](https://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/collect/HashBiMap.java), saving [nearly 40% on memory from the traditional pair of `HashMap`s](https://code.google.com/p/guava-libraries/source/detail?r=72a25f66b25db2c957bf8f287c2e54baf418d514). (`ImmutableBiMap` is similar.) – Louis Wasserman Mar 09 '13 at 17:57
  • @jlordo: Sure, but it shares data between the two hash tables with a custom-built data structure. That's not the same thing as just wrapping two `Map`s. – Louis Wasserman Mar 09 '13 at 18:01
  • @LouisWasserman: Yes, just saw it, and edited my previous comment ;) Learned something new about the greatness of Guava today. Thanks. – jlordo Mar 09 '13 at 18:03
  • 2
    No worries. (The rewrite of `HashBiMap` is also super-recent, being only released with Guava 14 a week or two ago. Also, I'm the one who rewrote it, so I have a special interest in such things.) – Louis Wasserman Mar 09 '13 at 18:07
5

Louis mentioned the memory savings possible in a BiMap implementation. That's the only thing that you can't get by wrapping two Map instances. Still, if you let us wrap the Map instances for you, we can take care of a few edges cases. (You could handle all these yourself, but why bother? :))

  • If you call put(newKey, existingValue), we'll error out immediately to keep the two maps in sync, rather than adding the entry to one map before realizing that it conflicts with an existing mapping in the other. (We provide forcePut if you do want to override the existing value.) We provide similar safeguards for inserting null or other invalid values.
  • BiMap views keep the two maps in sync: If you remove an element from the entrySet of the original BiMap, its corresponding entry is also removed from the inverse. We do the same kind of thing in Entry.setValue.
  • We handle serialization: A BiMap and its inverse stay "connected," and the entries are serialized only once.
  • We provide a smart implementation of inverse() so that foo.inverse().inverse() returns foo, rather than a wrapper of a wrapper.
  • We override values() to return a Set. This set is identical to what you'd get from inverse().keySet() except that it maintains the same iteration order as the original BiMap.
Chris Povirk
  • 3,738
  • 3
  • 29
  • 47