Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
gissuebot opened this issue Oct 31, 2014 · 20 comments
Closed
Labels

Comments

@gissuebot
Copy link

gissuebot commented Oct 31, 2014

Original issue created by j...@nwsnet.de on 2010-10-28 at 08:59 AM


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 (#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.

@gissuebot
Copy link
Author

Original comment posted by ray.j.greenwell on 2010-10-29 at 08:51 PM


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...

@gissuebot
Copy link
Author

Original comment posted by ray.j.greenwell on 2010-10-29 at 09:07 PM


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

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2010-11-05 at 10:15 AM


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).

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2010-11-05 at 10:35 AM


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.

@gissuebot
Copy link
Author

Original comment posted by ray.j.greenwell on 2010-11-05 at 11:26 PM


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.

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2010-11-11 at 02:26 PM


This request of mine seems to be very similar to issue #56 (#56 though not limited to a set for the keys.

@gissuebot
Copy link
Author

Original comment posted by fry@google.com on 2011-01-13 at 08:37 PM


Have you considered using MapMaker.makeComputingMap?

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2011-01-14 at 09:49 AM


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

@gissuebot
Copy link
Author

Original comment posted by fry@google.com on 2011-01-14 at 03:00 PM


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.

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2011-01-24 at 11:17 AM


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.

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2011-07-18 at 03:38 PM


(No comment entered for this change.)


Status: Accepted
Labels: Type-Enhancement

@gissuebot
Copy link
Author

Original comment posted by dancerjohn on 2011-09-04 at 08:45 PM


I feel that rather than an implementation as proposed above a more generic solution as proposed in #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.

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2011-09-05 at 06:21 AM


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.

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2011-10-20 at 09:02 PM


What is the feeling on strict versus lazy filling here?

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2011-10-21 at 09:49 AM


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?

@gissuebot
Copy link
Author

Original comment posted by fry@google.com on 2011-12-10 at 03:51 PM


(No comment entered for this change.)


Labels: Package-Collect

@gissuebot
Copy link
Author

gissuebot commented Oct 31, 2014

Original comment posted by j...@nwsnet.de on 2012-01-11 at 04:27 PM


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?

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-01-20 at 04:58 AM


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.

@gissuebot
Copy link
Author

Original comment posted by wasserman.louis on 2012-02-23 at 07:26 PM


How is this different from issue 56, except that it'd accept an Iterable of keys?

@gissuebot
Copy link
Author

Original comment posted by kevinb@google.com on 2012-02-24 at 09:07 PM


I'll dup this out.


Status: Duplicate
Merged Into: #56

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant