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;
        }
     ));