我有
List<Gift> gifts = new ArrayList<>();
gifts .add(new Gift().withType(INF, CHD));
gifts .add(new Gift().withType(ADT, CHD));
gifts .add(new Gift().withType(INF, ADT));
礼品有一种方法List<Type> getTypes()
;
现在我想把礼物清单变成类似的东西
Map<Type,List<Gift>>
。
我想在一行中使用Java 8和lambdas。有可能吗?
public class Gift {
public List<Type> getTypes() {
return types;
}
public Gift withType(Type... types) {
this.types = Arrays.asList(types);
return this;
}
List<Type> types = new ArrayList<>();
}
public enum Type {
ADT,
CHD,
INF;
}
以前的旧代码(看起来非常糟糕)。这就是我的全部。
Map<Type, List<Gift>> byTypes = new HashMap<>();
for (Gift gift : gifts) {
for (Type type : gift.getTypes()) {
List<Gift> giftList = byTypes.get(type);
if (giftList == null) {
giftList = new ArrayList<>();
}
giftList.add(gift);
byTypes.put(type,giftList);
}
}
答案 0 :(得分:3)
使用Guava的Multimap:
ListMultimap<Type, Gift> multimap = ArrayListMultimap.create();
gifts.forEach(g -> g.getTypes().forEach(t -> multimap.put(t, g)));
Map<Type, Collection<Gift>> map = multimap.asMap();
答案 1 :(得分:1)
好的,我找到了满足我的解决方案:-)我写了我的收藏家:-D
Map<Type, List<Gift>> collect1 = gifts.stream().collect(new TypeToManyGiftCollector());
public class TypeToManyGiftCollector
implements Collector<Gift, Map<Type, List<Gift>>, Map<Type, List<Gift>>> {
@Override
public Supplier<Map<Type, List<Gift>>> supplier() {
return () -> new HashMap<Type, List<Gift>>() {{
for (Type type : Type.values()) {
put(type, new ArrayList<Gift>());
}
}};
}
@Override
public BiConsumer<Map<Type, List<Gift>>, Gift> accumulator() {
return (Map<Type, List<Gift>> map, Gift gift) -> {
gift.getTypes().stream().forEach(type -> map.get(type).add(gift));
};
}
@Override
public BinaryOperator<Map<Type, List<Gift>>> combiner() {
return (Map<Type, List<Gift>> map1, Map<Type, List<Gift>> map2) ->
{
for (Type type : Type.values()) {
map1.get(type).addAll(map2.get(type));
}
return map1;
};
}
@Override
public Function<Map<Type, List<Gift>>, Map<Type, List<Gift>>> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH));
}
}
答案 2 :(得分:0)
重新引入中间对类P
,但方式略有不同。我想我们可能期望在以后的Java迭代中,这将成为更常见的地方,并且更容易引入内置的Pair类型和Value Objects的实现。
package play;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static play.Type.*;
public class Play {
static class P<K,V> { K k; V v; P(K kk,V vv) {k=kk;v=vv;}}
public static void main(String[] args) throws IOException {
List<Gift> gifts = new ArrayList<>();
gifts .add(new Gift().withType(INF, CHD));
gifts .add(new Gift().withType(ADT, CHD));
gifts .add(new Gift().withType(INF, ADT));
Map<Type,List<Gift>> m = gifts.stream()
.flatMap((g)->g.getTypes().stream().map((t)->new P<>(t,g)))
.collect(
Collectors.groupingBy(
(p)->p.k,
// Does not work with <code>new EnumMap<>(Type.class)</code>
// I dont know why, ...
()->new EnumMap(Type.class),
Collectors.mapping(
(p)->p.v,
Collectors.toList()
)
)
);
System.out.println("Map: "+m.toString());
}
}
我在这段代码中唯一的问题是我无法解释是否需要将“无类型”地图作为地图工厂。如果您知道原因,请随时解释一下......
答案 3 :(得分:0)
我用reduce方法找到了其他解决方案。在我看来,较小的一个,更容易理解。
HashMap<Type, List<Gift>> result = gifts.stream().reduce(
new HashMap<Type, List<Gift>>() {{
asList(Type.values()).stream().forEach(type -> put(type, new ArrayList<>()));
}}
,
(map, gift) -> {
gift.getTypes().stream().forEach(type -> map.get(type).add(gift));
return map;
}
,
(map1, map2) -> {
asList(Type.values()).stream().forEach(type -> map1.get(type).addAll(map2.get(type)));
return map1;
}
);