问题
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