13

I really like the Multimap class of the google guava library. It is a map type where you can add multiple values for a key, so it effectively maps from a key to a collection of some type. What I especially love is the Multimaps.index() function which takes an Iterable and a key function and returns a Multimap which groups (or indexes or maps) the elements of the Iterable by the value the function returns for each of those elements.

What I find a bit strange is that Multimap.values() returns a flat collection instead of a collection of collections? So the grouping the index function gave me is lost once Ì retrieve the values. I can circumvent that problem by calling Multimap.asMap() and then call values() on that.

Does anyone know why it may make sense that Multimap behaves that way?

CubeJockey
  • 2,209
  • 8
  • 24
  • 31
nansen
  • 2,912
  • 1
  • 20
  • 33

2 Answers2

15

Multimap.asMap().values() isn't a way around the problem -- it was deliberate that Multimap provides both ways of accessing it, getting a Collection<Collection<V>> via asMap().values() and getting the flattened Collection<V> with values().

More generally speaking, Multimap tries not to just be "a map to collections," but rather "a general way to associate keys with multiple values." So you get the entries() method in addition to values() and keys(). The asMap() view provides a way to treat it as a "map to collections," but that has very different semantics that aren't always what you're looking for.

In any event, the values method is just meant to fill a different niche than the one filled by asMap().values().

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Grouping is what I usually use Multimap for, so by 'problem' I meant problem of my domain, not problem of the Multimap-API. Should not sound like i was criticizing the API. Just didn't quite understand the philosophy behind it. Thanks for your answer. – nansen Mar 28 '12 at 21:10
  • 2
    @nansen: It's not like Multimap is trying to hide that the two concepts overlap (e.g., you can always iterate through `keys()` and do a `get(key)` to get the collection of values for that key). The understanding is simply that if you ask for all the values in the multimap, you don't care about the associated keys, just like with a normal map. And for all other cases it gives you a live view for viewing it as a `Map>`. You realize that `asMap` doesn't do any copying, right? It's just a different view of the same data, so the overhead is negligible. – Mark Peters Mar 28 '12 at 21:14
  • 1
    I like this view of things because it expresses a key principle of reusability. Like Alan Perlis says: "It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures." – nansen Mar 28 '12 at 21:24
  • It's definitely true that we like providing views -- it makes it much simpler to operate on the same structure in many different ways. – Louis Wasserman Mar 28 '12 at 21:25
6

Does anyone know why it may make sense that Multimap behaves that way?

A Multimap should be viewed as ordinary map, where the keys does not need to be unique.

Key       Val
 a   ->    1
 b   ->    2
 a   ->    3

Values: {1, 2, 3}
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 1
    I think what you're getting at is that an *ordinary* map does not associate the values returned from `values()` with their keys (besides iteration order), so why should a Multimap depart from that convention? And if so, I agree. – Mark Peters Mar 28 '12 at 21:00
  • Yep. That's another way of putting it. – aioobe Mar 28 '12 at 21:01