简体   繁体   English

Java 8流将List项减少并组合到Map

[英]Java 8 streams reduce and combine List items to Map

I need to create map with keys of name1/2 summing values value1/2. 我需要使用name1 / 2求和值value1 / 2的键创建映射。

What could be the cleanest way to rewrite this using java 8 streams? 什么可能是使用java 8流重写这个最干净的方法?

class Item {

    private String name1;
    private Integer value1;
    private String name2;
    private Integer value2;

    public Item(final String name1, final Integer value1, final String name2, final Integer value2) {
        this.name1 = name1;
        this.value1 = value1;
        this.name2 = name2;
        this.value2 = value2;
    }
    //getters and setters
}
List<Item> list = Lists.newArrayList(
                new Item("aaa", 1, "bbb", 2),
                new Item("bbb", 5, "ccc", 3),
                new Item("aaa", 8, "bbb", 7),
                new Item("bbb", 2, "aaa", 5));

Map<String, Integer> map = Maps.newHashMap();

for (Item item : list) {
    map.merge(item.name1, item.value1, Integer::sum);
    map.merge(item.name2, item.value2, Integer::sum);
}

System.out.println(map);//{aaa=14, ccc=3, bbb=16}

A possible solution is to flat map each item into a stream made by two entries: each entry will be composed of the name and the corresponding value. 一种可能的解决方案是将每个项目平面映射到由两个条目组成的流中:每个条目将由名称和相应的值组成。 Then, this is collected into a map by summing the values of the values having the same key. 然后,通过对具有相同键的值的值求和,将其收集到映射中。 Since there is no built-in pair to hold both values, we can use AbstractMap.SimpleEntry . 由于没有内置对来保存这两个值,我们可以使用AbstractMap.SimpleEntry

Map<String, Integer> map =
    list.stream()
        .flatMap(i -> Stream.of(new AbstractMap.SimpleEntry<>(i.name1, i.value1), new AbstractMap.SimpleEntry<>(i.name2, i.value2)))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Integer::sum));

Alternatively, it might be simpler to just use a custom collect call. 或者,仅使用自定义collect呼叫可能更简单。 The accumulator merges each key, just like what you have in the for loop body. 累加器合并每个键,就像你在for循环体中一样。 The tricky part is the combiner, which in this case merges two maps together by iterating over the entries of the second map and merging them into the first one. 棘手的部分是组合器,在这种情况下,通过迭代第二个映射的条目并将它们合并到第一个映射中,将两个映射合并在一起。

Map<String, Integer> map =
        list.stream()
            .collect(
                HashMap::new,
                (m, i) -> {
                    m.merge(i.name1, i.value1, Integer::sum);
                    m.merge(i.name2, i.value2, Integer::sum);
                },
                (m1, m2) -> m2.forEach((k, v) -> m1.merge(k, v, Integer::sum))
            );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM