我有一个列表< Foo>并想要一个番石榴Multimap< String,Foo>我们把它们的Collection< String>的每个标签分成了Foo getTags()函数.
我使用java 8,所以lambdas和方法引用是罚款/鼓励.
例如,如果我有:
foo1,tags=a,b,c foo2,tags=c,d foo3,c,e
我会得到一个Multimap< String,Foo>有:
a -> foo1,foo3 b -> foo1 c -> foo1,foo2,foo3 d -> foo2 e -> foo3
解决方法
您可以使用自定义收藏夹:
Multimap<String,Foo> map = list.stream().collect( ImmutableMultimap::builder,(builder,value) -> value.getTags().forEach(tag -> builder.put(tag,value)),(builder1,builder2) -> builder1.putAll(builder2.build()) ).build();
这不会引起额外的副作用(参见here),是并发的,比较惯用的.
您还可以将这些特别的羔羊提取成一个完整的收藏家,如下所示:
public static <T,K> Collector<T,?,Multimap<K,T>> toMultimapByKey(Function<? super T,? extends Iterable<? extends K>> keysMapper) { return new MultimapCollector<>(keysMapper); } private static class MultimapCollector<T,K> implements Collector<T,ImmutableMultimap.Builder<K,T>,T>> { private final Function<? super T,? extends Iterable<? extends K>> keysMapper; private MultimapCollector(Function<? super T,? extends Iterable<? extends K>> keysMapper) { this.keysMapper = keysMapper; } @Override public Supplier<ImmutableMultimap.Builder<K,T>> supplier() { return ImmutableMultimap::builder; } @Override public BiConsumer<ImmutableMultimap.Builder<K,T> accumulator() { return (builder,value) -> keysMapper.apply(value).forEach(k -> builder.put(k,value)); } @Override public BinaryOperator<ImmutableMultimap.Builder<K,T>> combiner() { return (b1,b2) -> b1.putAll(b2.build()); } @Override public Function<ImmutableMultimap.Builder<K,T>> finisher() { return ImmutableMultimap.Builder<K,T>::build; } @Override public Set<Characteristics> characteristics() { return Collections.emptySet(); } }
那么收藏将如下所示:
Multimap<String,Foo> map = list.stream().collect(toMultimapByKey(Foo::getTags));
如果您的订单不重要,您还可以从特性()方法返回EnumSet.of(Characteristics.UNORDERED).这可以使内部收集机械更有效地起作用,特别是在并行还原的情况下.