guava/src/com/google/common/collect/Multimaps.java
public static <K, V> ImmutableListMultimap<K, V> index(
      Iterable<V> values, Function<? super V, K> keyFunction) {
    return index(values.iterator(), keyFunction);
  }
public static <K, V> ImmutableListMultimap<K, V> index(
      Iterable<V> values, Function<? super V, K> keyFunction) {
    return index(values.iterator(), keyFunction);
  }
Creates an index {@code ImmutableListMultimap} that contains the results of applying a
specified function to each item in an {@code Iterable} of values. Each value will be stored as
a value in the resulting multimap, yielding a multimap with the same size as the input
iterable. The key used to store that value in the multimap will be the result of calling the
function on that value. The resulting multimap is created as an immutable snapshot. In the
returned multimap, keys appear in the order they are first encountered, and the values
corresponding to each key appear in the same order as they are encountered.

<p>For example,

<pre>{@code
List<String> badGuys =
Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Function<String, Integer> stringLengthFunction = ...;
Multimap<Integer, String> index =
Multimaps.index(badGuys, stringLengthFunction);
System.out.println(index);
}</pre>

<p>prints

<pre>{@code
{4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]}
}</pre>

<p>The returned multimap is serializable if its keys and values are all serializable.

@param values the values to use when constructing the {@code ImmutableListMultimap}
@param keyFunction the function used to produce the key for each value
@return {@code ImmutableListMultimap} mapping the result of evaluating the function {@code
keyFunction} on each value in the input collection to that value
@throws NullPointerException if any element of {@code values} is {@code null}, or if {@code
keyFunction} produces {@code null} for any key