从java8流创建番石榴MultiMap的最简洁方法

Sco*_*t B 48 guava java-8 java-stream

我有一个List<Foo>并且想要一个Multimap<String, Foo>我们Foo根据他们的getId()功能对其进行分组的地方.

我正在使用Java 8,它几乎可以做到:

List<Foo> foos = ...
Map<String, List<Foo>> foosById = foos.stream().collect(groupingBy(Foo::getId));
Run Code Online (Sandbox Code Playgroud)

但是,我有大量的代码需要一个,MultiMap<String, Foo>所以这并没有为我节省任何东西,我回到使用for循环来创建我的MultiMap.我错过了一个很好的"功能性"方式吗?

Bur*_*urg 87

您可以使用Guava Multimaps工厂:

Multimaps.index(foos, Foo::getId);
Run Code Online (Sandbox Code Playgroud)

或使用Collector接口对Multimaps.index进行调用(如下所示,在未经优化的朴素实现中).

Multimap<String, Foo> collect = foos.stream().collect(MultimapCollector.toMultimap(Foo::getId));
Run Code Online (Sandbox Code Playgroud)

和收藏家:

public class MultimapCollector<T, K, V> implements Collector<T, Multimap<K, V>, Multimap<K, V>> {

    private final Function<T, K> keyGetter;
    private final Function<T, V> valueGetter;

    public MultimapCollector(Function<T, K> keyGetter, Function<T, V> valueGetter) {
        this.keyGetter = keyGetter;
        this.valueGetter = valueGetter;
    }

    public static <T, K, V> MultimapCollector<T, K, V> toMultimap(Function<T, K> keyGetter, Function<T, V> valueGetter) {
        return new MultimapCollector<>(keyGetter, valueGetter);
    }

    public static <T, K, V> MultimapCollector<T, K, T> toMultimap(Function<T, K> keyGetter) {
        return new MultimapCollector<>(keyGetter, v -> v);
    }

    @Override
    public Supplier<Multimap<K, V>> supplier() {
        return ArrayListMultimap::create;
    }

    @Override
    public BiConsumer<Multimap<K, V>, T> accumulator() {
        return (map, element) -> map.put(keyGetter.apply(element), valueGetter.apply(element));
    }

    @Override
    public BinaryOperator<Multimap<K, V>> combiner() {
        return (map1, map2) -> {
            map1.putAll(map2);
            return map1;
        };
    }

    @Override
    public Function<Multimap<K, V>, Multimap<K, V>> finisher() {
        return map -> map;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return ImmutableSet.of(Characteristics.IDENTITY_FINISH);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在大多数情况下,不可变的multimap正是您应该想要的. (7认同)
  • `Multimaps.index`返回一个*immutable*`Multimap`,这可能不是你想要的. (5认同)
  • 我写了一个ImmutableMultimapCollector:https://medium.com/@robertmassaioli/an-immutablemultimapcollector-for-guava-3f141f9040f#.m18fnmgwo (2认同)

M. *_*tin 21

Guava 21.0 引入了几种返回Collector实例的方法,这些实例将根据将函数应用于其元素的结果将 a 转换Stream为分组。Multimap这些方法是:

\n\n
ImmutableListMultimap<String, Foo> foosById = foos.stream().collect(\n        ImmutableListMultimap.toImmutableListMultimap(\n                Foo::getId, Function.identity()));\n
Run Code Online (Sandbox Code Playgroud)\n
ImmutableSetMultimap<String, Foo> foosById = foos.stream().collect(\n        ImmutableSetMultimap.toImmutableSetMultimap(\n                Foo::getId, Function.identity()));\n
Run Code Online (Sandbox Code Playgroud)\n
HashMultimap<String, Foo> foosById = foos.stream().collect(\n        Multimaps.toMultimap(\n                Foo::getId, Function.identity(), HashMultimap::create)\n);\n
Run Code Online (Sandbox Code Playgroud)\n