Java streams sum values of a List of Maps

感情迁移 提交于 2020-11-29 19:13:40

问题


i want to determine the of the "columns" in "rows" or or better: Build sum of a list of maps like List> rows

Is it somehow possible to sum all values of each distinct column? The function shall return a Map with the column as key and the sum of all values as value.

summMap.get("columname")

Let's assume i have the following list of maps:

List<Map<String, Long>> mapList = new ArrayList();
Map<String, Object> map1 = new HashMap<>();
Map<String, Object> map2 = new HashMap<>();
Map<String, Object> map3 = new HashMap<>();
map1.put("col1", 90);
map1.put("col2", 50);
map1.put("col3", 10);
map2.put("col1", 90);
map2.put("col2", 50);
map2.put("col3", 10);
map3.put("col1", 90);
map3.put("col2", 50);
map3.put("col3", 10);
mapList.add(map1);
mapList.add(map2);
mapList.add(map3);
Map<String, Long> sum = mapList.stream().distinct().sum() // Example
// result i'm awaiting/expecting
Long sumVal1 = sum.get("col1"); // 270
Long sumVal2 = sum.get("col2"); // 150
Long sumVal3 = sum.get("col3"); // 30

Long sumVal = sum.get("col1");


回答1:


Here is the simple solution, it will give the result as per your requirement:

List<Map<String, Long>> mapList = new ArrayList();
Map<String, Long>       map1    = new HashMap<>();
Map<String, Long>       map2    = new HashMap<>();
Map<String, Long>       map3    = new HashMap<>();
map1.put("col1", 90L);
map1.put("col2", 50L);
map1.put("col3", 10L);
map2.put("col1", 90L);
map2.put("col2", 50L);
map2.put("col3", 10L);
map3.put("col1", 90L);
map3.put("col2", 50L);
map3.put("col3", 10L);
mapList.add(map1);
mapList.add(map2);
mapList.add(map3);

Map<String, Long> sum = new HashMap<>();
mapList.forEach(map -> map.keySet().forEach(
                s -> {
                    mapList.stream()
                           .collect(Collectors.groupingBy(foo -> s,
                                Collectors.summingLong(foo -> map.get(s)))).forEach(
                                    (id, sumTargetCost) ->
                                            sum.put(s, sumTargetCost)
                    );
                }

));

Long sumVal1 = sum.get("col1"); // 270
Long sumVal2 = sum.get("col2"); // 150
Long sumVal3 = sum.get("col3"); // 30

System.out.println("SumVal1: " + sumVal1 + ", SumVal2: " + sumVal2 + ", SumVal3: " + sumVal3);



回答2:


It’s as simple as

Map<String, Long> sum = mapList.stream()
    .flatMap(m -> m.entrySet().stream())
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Long::sum));



回答3:


Holger has already provided a clean solution, but I think you can also try flatMap and groupingBy as:

Map<String, Long> sum = mapList.stream().flatMap(map -> map.entrySet().stream())
                .collect(groupingBy(Map.Entry::getKey, summingLong(Map.Entry::getValue)));

The whole solution to your question:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.stream.Collectors.*;

public class ListMapSum {
    public static void main(String... args) {
        List<Map<String, Long>> mapList = new ArrayList();
        Map<String, Long> map1 = new HashMap<>();
        Map<String, Long> map2 = new HashMap<>();
        Map<String, Long> map3 = new HashMap<>();
        map1.put("col1", 90L);
        map1.put("col2", 50L);
        map1.put("col3", 10L);
        map2.put("col1", 90L);
        map2.put("col2", 50L);
        map2.put("col3", 10L);
        map3.put("col1", 90L);
        map3.put("col2", 50L);
        map3.put("col3", 10L);
        mapList.add(map1);
        mapList.add(map2);
        mapList.add(map3);
        Map<String, Long> sum = mapList.stream().flatMap(map -> map.entrySet().stream())
                .collect(groupingBy(Map.Entry::getKey, summingLong(Map.Entry::getValue)));
        Long sumVal1 = sum.get("col1"); // 270
        Long sumVal2 = sum.get("col2"); // 150
        Long sumVal3 = sum.get("col3"); // 30
    }
}



回答4:


This doesn't support parallel execution, but could do by modifying the last argument in reduce:

private static Map<String, Long> reduceLongs(List<Map<String, Long>> maps) {
    return maps.stream()
        .flatMap(map -> map.entrySet().stream())
        .reduce(new HashMap<>(), (map, e) -> {
            map.compute(e.getKey(), (k ,v) -> v == null ? e.getValue() : e.getValue() + v);
            return map;
        }, (m1, m2) -> { throw new UnsupportedOperationException(); });
}

And a passing test:

final List<Map<String, Long>> maps = new ArrayList<>();

Map<String, Long> map1 = new HashMap<>();
Map<String, Long> map2 = new HashMap<>();

map1.put("col1", 90L);
map1.put("col2", 50L);

map2.put("col1", 90L);
map2.put("col2", 50L);

map2.put("col3", 100L);

maps.add(map1);
maps.add(map2);

final Map<String, Long> sums = reduceLongs(maps);

assertEquals(180L, sums.get("col1").longValue());
assertEquals(100L, sums.get("col2").longValue());
assertEquals(100L, sums.get("col3").longValue());


来源:https://stackoverflow.com/questions/52294639/java-streams-sum-values-of-a-list-of-maps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!