maidh91 / guava-libraries

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

Create equivalent to `Maps.uniqueIndex` that takes keys instead of values #460

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Every now and then, especially when grouping data for reporting-related 
functionality, I find myself in situations where I intuitively would use what

  uniqueIndex(Iterable<V> values, Function<? super V,K> keyFunction)

provides, but instead of adding the iterable's elements as values and applying 
the given function to it to generate the corresponding keys, I'd like it the 
other way round, i.e. add the elements as keys and generate the values from 
them using a function.

I think this could also be used to cover #331 
(http://code.google.com/p/guava-libraries/issues/detail?id=331), but instead of 
directly supplying a default value, one would pass in a function that always 
returns a fixed value (or a new instance each, depending on the type).

Such a method is to me the long-time missing partner for `uniqueIndex`, please 
consider adding it.

P.S.: Yes, I considered the fact that keys have different attributes in maps 
than values, but at least one can expect users of this method to know what they 
are doing (and document it, too, for that matter). E.g., if an iterable with 
equal elements is passed to the method, the map would have less keys than the 
iterable has/had elements, and the given function would be applied redundantly 
as its results get discarded or replaced in the map.

Original issue reported on code.google.com by j...@nwsnet.de on 28 Oct 2010 at 8:59

GoogleCodeExporter commented 9 years ago
I can definitely see utility in this.

public static Map<K, V> transformedSet (Set<K> set, Function<? super K, V> 
function)

Attached is an immutable version that I already have written...

Original comment by ray.j.gr...@gmail.com on 29 Oct 2010 at 8:51

Attachments:

GoogleCodeExporter commented 9 years ago
(Just noticed my impl doesn't have a nice size(), well, it's just an example of 
the idea..)

Original comment by ray.j.gr...@gmail.com on 29 Oct 2010 at 9:07

GoogleCodeExporter commented 9 years ago
And I could use this method again right now. I'd like to map a bunch of integer 
sets to dynamically generated directory names (e.g. {4, 8, 15} -> "4_8_15/"; 
yes, sorting is clever here).

Original comment by j...@nwsnet.de on 5 Nov 2010 at 10:15

GoogleCodeExporter commented 9 years ago
My implementation approach is this:

      public static <K, V> ImmutableMap<K, V> fromKeys(Iterable<K> keys, Function<? super K, V> valueFunction) {
        Preconditions.checkNotNull(valueFunction, "Value function must not be null.");
        ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
        for (K key : keys) {
          builder.put(key, valueFunction.apply(key));
        }
        return builder.build();
      }

However, I feel that there is some generalization (e.g. `? extends` or `? 
super`) missing, probably for the key type, but I can't figure out exactly 
where and what.

Original comment by j...@nwsnet.de on 5 Nov 2010 at 10:35

GoogleCodeExporter commented 9 years ago
I think it's right the way it is.

You could potentially pass in Iterable<? extends K> keys, so that you could 
create a Map with a generic keytype that is a superclass of your Iterable type. 
(Turn a List<Integer> into a Map<Number, V>) I guess you could also have the 
function return <? extends V>.

But why throw away that valuable information? If you have List<Integer>, 
wouldn't you want it built into a Map<Integer, V>?

If you have some other method that consumes this map, then it should be the one 
with wildcards: foo(Map<? extends Number, ? extends Foo> inputMap)

I could see both approaches being added to Maps: create an ImmutableMap, or 
return a Map that is a view of a key Set.

Original comment by ray.j.gr...@gmail.com on 5 Nov 2010 at 11:26

GoogleCodeExporter commented 9 years ago
This request of mine seems to be very similar to issue #56 
(http://code.google.com/p/guava-libraries/issues/detail?id=56&q=enum), though 
not limited to a set for the keys.

Original comment by j...@nwsnet.de on 11 Nov 2010 at 2:26

GoogleCodeExporter commented 9 years ago
Have you considered using MapMaker.makeComputingMap?

Original comment by fry@google.com on 13 Jan 2011 at 8:37

GoogleCodeExporter commented 9 years ago
As I basically noted on #331: `MapMaker`'s concurrency and expiration 
functionality is what makes me feel uncomfortable. AFAIS from the 
implementation, there is some overhead at least in the (super) constructor that 
should be unnecessary for the use case above. And as I haven't dealt with 
concurrent maps yet, I'm unfamiliar with that topic.

In a nutshell: Why should I accept a `ConcurrentMap` when all I need is a 
(e.g.) `HashMap`?

If the overhead is insignificant, `MapMaker` would probably be a possible 
solution. But for now, I'd prefer a dedicated method as described above.

Please enlighten me :)

Original comment by j...@nwsnet.de on 14 Jan 2011 at 9:49

GoogleCodeExporter commented 9 years ago
You don't pay a price for MapMaker functionality which you don't use.

A ConcurrentMap with concurrency level of 1 is basically the same as a HashMap. 
Or if you're going to have concurrent access, then use a higher concurrency 
level.

Original comment by fry@google.com on 14 Jan 2011 at 3:00

GoogleCodeExporter commented 9 years ago
It seems I fail to see how `MapMaker` can be really used here. I'm looking for 
an already filled, immutable map. However, `MapMaker.makeComputingMap()` seems 
to require me to copy it.

In any case: My aforementioned `fromKeys` implementation has already been shown 
in issue #56 before, so I'd say there is a natural demand for a method with the 
described functionality.

P.S.: Is there a reference on how to create links to issues, VCS revisions etc. 
in issue tracker comments? Looks like I did that before, but that was somewhat 
by accident. I had neither success view my comments' source nor reading the 
issue tracker FAQ and docs.

Original comment by j...@nwsnet.de on 24 Jan 2011 at 11:17

GoogleCodeExporter commented 9 years ago

Original comment by kevinb@google.com on 18 Jul 2011 at 3:38

GoogleCodeExporter commented 9 years ago
I feel that rather than an implementation as proposed above a more generic 
solution as proposed in 
http://code.google.com/p/guava-libraries/issues/detail?id=679 would be of 
greater use. It allows for the passing of an iterable to create a map but takes 
two functions, one for creating keys one for creating values. The identity 
function may be passed as either of the accepted functions to create the 
functionality described above or in issue 56.

Original comment by dancerj...@gmail.com on 4 Sep 2011 at 8:45

GoogleCodeExporter commented 9 years ago
With my original suggestion here, I see the advantage that one might use 
already existing functions (both in Guava and in the application; say, getting 
the name of an enum) more often.

Original comment by j...@nwsnet.de on 5 Sep 2011 at 6:21

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
What is the feeling on strict versus lazy filling here?

Original comment by wasserman.louis on 20 Oct 2011 at 9:02

GoogleCodeExporter commented 9 years ago
I'm not sure, but the lazy part sounds like hard-to-track behaviour in cases 
where not all map entries are further processed right after calling such a 
method.

I guess you have an opinion that you could share?

Original comment by j...@nwsnet.de on 21 Oct 2011 at 9:49

GoogleCodeExporter commented 9 years ago

Original comment by fry@google.com on 10 Dec 2011 at 3:51

GoogleCodeExporter commented 9 years ago
I'd like to revive this ticket and the ones connected to it (issue #56, issue 
#331 etc.) as I still find myself in situations where I really need this.

`Maps.uniqueIndex` considers only one way of the mapping; a method for the 
other way is still lacking.

Generating keys from values might result in duplicates which would be a problem 
in a non-Multimap, but that is not the case when transforming keys to values.

How can we proceed to finally achieve a satisfying solution here?

Original comment by j...@nwsnet.de on 11 Jan 2012 at 4:27

GoogleCodeExporter commented 9 years ago
My preferred solution would be something like: return a lazily computed view of 
the set, but as something like MapView, analogous to Sets.SetView, which has a 
nice fluent syntax for copying to an immutable map or writing into a mutable 
map.

Getting a strictly computed map from a lazy view is straightforward; the other 
direction doesn't work.

Original comment by wasserman.louis on 20 Jan 2012 at 4:58

GoogleCodeExporter commented 9 years ago
How is this different from issue 56, except that it'd accept an Iterable of 
keys?

Original comment by wasserman.louis on 23 Feb 2012 at 7:26

GoogleCodeExporter commented 9 years ago
I'll dup this out.

Original comment by kevinb@google.com on 24 Feb 2012 at 9:07

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:15

GoogleCodeExporter commented 9 years ago

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