Java 使用流API将地图转换为其他地图
我有一个Java 使用流API将地图转换为其他地图,java,functional-programming,java-8,Java,Functional Programming,Java 8,我有一个Map(),我想生成一个Map,它是通过在Map.Entry中迭代List并对该成员列表中每个成员的每个Map条目的键求和来计算的。没有非功能性的方法很容易,但如果不使用Java8流API编写自定义收集器,我就找不到一种方法。我想我需要类似于Stream.collect(Collectors.toFlatMap)的东西,但是在Collectors中没有这样的方法 我能找到的最好的方法是: longListOfMemberMap = new HashMap<Long,
Map()
,我想生成一个Map
,它是通过在Map.Entry
中迭代List
并对该成员列表中每个成员的每个Map条目的键求和来计算的。没有非功能性的方法很容易,但如果不使用Java8流API编写自定义收集器,我就找不到一种方法。我想我需要类似于Stream.collect(Collectors.toFlatMap)
的东西,但是在Collectors
中没有这样的方法
我能找到的最好的方法是:
longListOfMemberMap = new HashMap<Long, List<Member>>()
longListOfMemberMap.put(10, asList(member1, member2));
Map<Member, Long> collect = longListOfMemberMap.entrySet().stream()
.collect(new Collector<Map.Entry<Long, List<Member>>, Map<Member, Long>, Map<Member, Long>>() {
@Override
public Supplier<Map<Member, Long>> supplier() {
return HashMap::new;
}
@Override
public BiConsumer<Map<Member, Long>, Map.Entry<Long, List<Member>>> accumulator() {
return (memberLongMap, tokenRangeListEntry) -> tokenRangeListEntry.getValue().forEach(member -> {
memberLongMap.compute(member, new BiFunction<Member, Long, Long>() {
@Override
public Long apply(Member member, Long aLong) {
return (aLong == null ? 0 : aLong) + tokenRangeListEntry.getKey();
}
});
});
}
@Override
public BinaryOperator<Map<Member, Long>> combiner() {
return (memberLongMap, memberLongMap2) -> {
memberLongMap.forEach((member, value) -> memberLongMap2.compute(member, new BiFunction<Member, Long, Long>() {
@Override
public Long apply(Member member, Long aLong) {
return aLong + value;
}
}));
return memberLongMap2;
};
}
@Override
public Function<Map<Member, Long>, Map<Member, Long>> finisher() {
return memberLongMap -> memberLongMap;
}
@Override
public Set<Characteristics> characteristics() {
return EnumSet.of(Characteristics.UNORDERED);
}
});
// collect is equal to
// 1. member1 -> 10
// 2. member2 -> 10
收集的值映射
:
然而,正如你所看到的,它比不起作用的方式要难看得多。我尝试了Collectors.toMap
和reduce方法Stream
,但我找不到一种方法来处理几行代码
对于这个问题,哪种方法最简单、最实用?longListOfMemberMap.entrySet().stream()
longListOfMemberMap.entrySet().stream()
.flatMap(entry -> entry.getValue().stream().map(
member ->
new AbstractMap.SimpleImmutableEntry<>(member, entry.getKey())))
.collect(Collectors.groupingBy(
Entry::getKey,
Collectors.summingLong(Entry::getValue)));
.flatMap(条目->条目.getValue().stream().map(
成员->
新的AbstractMap.SimpleImmutableEntry(成员,entry.getKey()))
.collect(收集器.groupingBy(
条目::getKey,
Collectors.summingLong(Entry::getValue));
…虽然一个更简单但更重要的替代方案可能看起来像
Map<Member, Long> result = new HashMap<>();
longListOfMemberMap.forEach((val, members) ->
members.forEach(member -> result.merge(member, val, Long::sum)));
Map result=newhashmap();
longListOfMemberMap.forEach((val,成员)->
members.forEach(member->result.merge(member,val,Long::sum));
我要指出的是,如果依赖Collector.of
并将匿名类转换为lambdas,您发布的代码可以写得更简洁:
Map<Member, Long> result = longListOfMemberMap.entrySet().stream()
.collect(Collector.of(
HashMap::new,
(acc, item) -> item.getValue().forEach(member -> acc.compute(member,
(x, val) -> Optional.ofNullable(val).orElse(0L) + item.getKey())),
(m1, m2) -> {
m1.forEach((member, val1) -> m2.compute(member, (x, val2) -> val1 + val2));
return m2;
}
));
Map result=longListOfMemberMap.entrySet().stream()
收集(
HashMap::新建,
(acc,item)->item.getValue().forEach(成员)->acc.compute(成员,
(x,val)->可选.ofNullable(val).orElse(0L)+item.getKey(),
(m1,m2)->{
m1.forEach((成员,val1)->m2.compute(成员,(x,val2)->val1+val2));
返回m2;
}
));
这仍然很麻烦,但至少不是压倒性的。这些“每个成员的钥匙”是什么?我更新了问题@kockoThanks以获得答案。您对这两种解决方案有何看法?第二个更容易理解,但第一个似乎更实用。顺便说一句,我不是痴迷于函数式编程,只是想知道哪种方式更方便。:)我倾向于选项2,TBH。如果没有monster
新的AbstractMap.SimpleImmutableEntry
(可以用任何其他“pair”对象替换),我更喜欢第一个,因为它更具有自描述性。(在这种情况下,我会编写Multimap.entries().stream().collect(Collectors.groupingBy)(Entry::getValue,Collectors.summingLong)(Entry::getKey))
)还要注意,前者本质上是可并行的,而后者可能是串行的(除非结果映射允许并发合并)
Map<Member, Long> result = new HashMap<>();
longListOfMemberMap.forEach((val, members) ->
members.forEach(member -> result.merge(member, val, Long::sum)));
Map<Member, Long> result = longListOfMemberMap.entrySet().stream()
.collect(Collector.of(
HashMap::new,
(acc, item) -> item.getValue().forEach(member -> acc.compute(member,
(x, val) -> Optional.ofNullable(val).orElse(0L) + item.getKey())),
(m1, m2) -> {
m1.forEach((member, val1) -> m2.compute(member, (x, val2) -> val1 + val2));
return m2;
}
));