yf0994 / guava-libraries

Automatically exported from code.google.com/p/guava-libraries
Apache License 2.0
0 stars 0 forks source link

Multimap<K,V> view of Map<K,Collection<V>> #1165

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago

This is similar to Issue #737 except with a slightly different use case.  I 
want to transform a Map<K,Collection<V>> to a Multimap<K,V>, and have the 
resultant Multimap be a view over the map.  The Multimap does not need to be 
modifiable.

This is counter to the spirit of MultiMaps.newXXX, b/c they take ownership of 
the map and anyway require it to be empty, but seems very much in line with the 
semantics of Multimaps.forMap(), with the existing difficulty that you may be 
wrapping a map that has a key mapped to an empty collection.

Here are the use cases for which I currently use this behaviour (I wrote my 
own):

(1) Adapting old API written in terms of Map to new written in terms of 
Multimap:

Map<K,Set<V>> map1 = fromSomewhereElse()
Multimap<K,V> view = Multimaps2.forMap(map1)

---

(2) Multi-value lookups like task to procedure codes.  (Most similar to Issue 
#737, except there the function is Function<A,B>; here is Function<A,Set<B>>.)

Function<A,Set<B>> findB = ...;
Map<K,A> map1 = fromSomewhereElse()
Map<K,Set<B>> map2 = Maps.transformValues(map1, findB);
Multimap<K,V> mm = Multimaps3.forMap(map2);

---

(3) One may take the approach of Issue #737 and think of this request as an 
enhancement to Multimaps.transformValues(), where a Multimap<K,A> and a 
Function<A,Set<B>> could be converted to MultiMap<K,B>.  I didn't write this, 
but seems difficult to keep the semantics of SetMultimap this way if there were 
multiple values of A which resolved to same B)

Function<A,Set<B>> findB = ...;
Map<K,A> map1 = fromSomewhereElse()
Multimap<K,A> mm1 = Multimaps.forMap(map1);
Multimap<K,B> mm = Multimaps2.transformValues(mm1,findB);

---

Thank you for the consideration.  (And you know, the great library.)

-dg

Original issue reported on code.google.com by gil...@gmail.com on 11 Oct 2012 at 9:18

GoogleCodeExporter commented 9 years ago
I suspect the decision to do this or not will primarily be philosophical, not a 
matter of implementation details.  We've been pretty insistent that Multimap is 
not just a wrapper around a Map to Collections, but that Multimap is a map from 
keys to multiple values that may or may not be implemented in terms of a Map of 
Collections.

Additionally, there are some funky edge cases that make me pretty deeply 
uncomfortable.

- What if the Map maps a key to an empty collection?  The Multimap spec says 
that that multimap.containsKey(key) is false in that case.
- What if the Map maps a key to null?
- What if you create a Multimap view of the Map and then someone puts null into 
the map?  The Multimap is basically corrupted now, but it can't find that out 
without a full linear-time traversal.

Original comment by lowas...@google.com on 11 Oct 2012 at 9:43

GoogleCodeExporter commented 9 years ago
> I suspect the decision to do this or not will primarily be philosophical, not 
a matter of implementation details.

I have no problem with this.

----

Here is how I handled the edge cases:

 - containsKey(key) implemented in terms of submap.containsKey(key) && submap.get(key).isEmpty() instead of just submap.containsKey(key).
 - A mapping to a null value is treated as non-existence. Multimap.get(key).add("x") replaces the mapping to null with a mapping to whatever is returned  from createCollection()
 - As for the final concern, Multimap.put is declared to accept both null keys and values, so both {null->["a","b"]} and {"y"->[null]} all seem acceptable to me.

Original comment by gil...@gmail.com on 11 Oct 2012 at 10:14

GoogleCodeExporter commented 9 years ago
A few issues with this idea:
-size() becomes O(#keys)
-get() would throw a NPE on access

We need to figure out what APIs to provide for interoperability between Maps 
and Multimaps.

Original comment by kak@google.com on 22 Aug 2013 at 10:42

GoogleCodeExporter commented 9 years ago
This issue has been migrated to GitHub.

It can be found at https://github.com/google/guava/issues/<id>

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:13

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:18

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 3 Nov 2014 at 9:08