How to merge 3 map of maps effectively in java - java

Merge below 3 maps if values exist then replace and if the value is new then add that value, for example :-
I have a Map1 as :-
{
BMW = {
SIZE=1,
SPEED=60
},
AUDI = {
SIZE=5,
SPEED=21
},
SEAT= {
SPEED=15
}
}
And a Map2 as :-
{
Suzuki = {
WHEELS_SIZE=2,
DOORS=3
},
AUDI = {
WHEELS_SIZE=5,
SIZE=4,
DOORS=5
},
SEAT= {
DOORS=4
}
}
And Map3 as :-
{
TOYOTA = {
WHEELS_SIZE=5,
DOORS=5
},
BMW= {
SIZE=10
}
}
I have a requirement to merge all 3 above so, that final map looks like
{
BMW = {
SIZE=10,
SPEED=60
},
AUDI = {
SIZE=4,
SPEED=21,
WHEELS_SIZE=5,
DOORS=5
},
SEAT= {
SPEED=15,
DOORS=4
},
Suzuki = {
WHEELS_SIZE=2,
DOORS=3
},
TOYOTA = {
WHEELS_SIZE=5,
DOORS=5
},
}
Could someone please suggest an optimized way to achieve this ? Thanks in advance!

Here is a naïve implementation:
public static void main(String[] args){
Map<String, Integer> BMW1 = new HashMap<>();
BMW1.put("SIZE", 1);
BMW1.put("SPEED", 60);
Map<String, Integer> AUDI1 = new HashMap<>();
AUDI1.put("SIZE", 5);
AUDI1.put("SPEED", 21);
Map<String, Integer> SEAT1 = new HashMap<>();
SEAT1.put("SPEED", 15);
Map<String, Map<String, Integer>> one =
Map.of("BMW", BMW1, "AUDI", AUDI1, "SEAT", SEAT1);
Map<String, Integer> SUZUKI2 = new HashMap<>();
SUZUKI2.put("WHEEL_SIZE", 2);
SUZUKI2.put("DOORS", 3);
Map<String, Integer> AUDI2 = new HashMap<>();
AUDI2.put("WHEELS_SIZE", 5);
AUDI2.put("SIZE", 4);
AUDI2.put("DOORS", 5);
Map<String, Integer> SEAT2 = new HashMap<>();
SEAT2.put("DOORS", 4);
Map<String, Map<String, Integer>> two =
Map.of("SUZUKI", SUZUKI2, "AUDI", AUDI2, "SEAT", SEAT2);
Map<String, Integer> TOYOTA3 = new HashMap<>();
TOYOTA3.put("WHEEL_SIZE", 5);
TOYOTA3.put("DOORS", 5);
Map<String, Integer> BMW3 = new HashMap<>();
BMW3.put("SIZE", 10);
Map<String, Map<String, Integer>> three =
Map.of("TOYOTA", TOYOTA3, "BMW", BMW3);
Map<String, Map<String, Integer>>[] maps = new Map[]{ one, two, three };
Map<String, Map<String, Integer>> mergedMaps = mergeMaps(maps);
printMap(mergedMaps);
}
public static Map<String, Map<String, Integer>> mergeMaps(Map<String, Map<String, Integer>>[] maps) {
Map<String, Map<String, Integer>> mergedMap = new HashMap<>();
for(Map<String, Map<String, Integer>> map : maps) {
for(Map.Entry<String, Map<String, Integer>> entry : map.entrySet()) {
if(mergedMap.containsKey(entry.getKey())){
Map<String, Integer> mergedCarStats = mergedMap.get(entry.getKey());
Map<String, Integer> carStats = entry.getValue();
mergedCarStats.putAll(carStats);
} else {
mergedMap.put(entry.getKey(), entry.getValue());
}
}
}
return mergedMap;
}
public static void printMap(Map<String, Map<String, Integer>> car) {
System.out.println("{");
for(Map.Entry<String, Map<String, Integer>> entry: car.entrySet()) {
System.out.println(String.format(" %s = {", entry.getKey()));
printStats(entry.getValue());
System.out.println(" },");
}
System.out.println("}");
}
public static void printStats(Map<String, Integer> stats) {
for(Map.Entry<String, Integer> entry : stats.entrySet()) {
System.out.println(String.format(" '%s': %d,", entry.getKey(), entry.getValue()));
}
}
If you run it you will get this output:
{
SUZUKI = {
'WHEEL_SIZE': 2,
'DOORS': 3,
},
SEAT = {
'SPEED': 15,
'DOORS': 4,
},
AUDI = {
'SPEED': 21,
'DOORS': 5,
'SIZE': 4,
'WHEELS_SIZE': 5,
},
TOYOTA = {
'WHEEL_SIZE': 5,
'DOORS': 5,
},
BMW = {
'SPEED': 60,
'SIZE': 10,
},
}
Which is what you asked for. There are a few things to consider though. Using loops this way is inefficient because the time complexity is going to be O(n^2) as there are 2 for loops. There are built in functions for merging maps since Java 8 which could be worth exploring.

Merge the three maps using java8
Map<String, Map<String, Integer>> resultMap = Stream.of(map1, map2, map3)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> new HashMap<String,Integer>(e.getValue()),
(key, value) -> {key.putAll(value); return key;}
));
Output:
{SEAT={SPEED=15, DOORS=4}, TOYOTA={WHEELS_SIZE=5, DOORS=5}, Suzuki={WHEELS_SIZE=2, DOORS=3}, AUDI={SPEED=21, WHEELS_SIZE=5, DOORS=5, SIZE=4}, BMW={SPEED=60, SIZE=10}}

Related

How can I not overwrite values via putAll() but instead add to the current value?

Suppose I have two hash maps:
HashMap <String, Integer> h1;
h1.put("hi", 30);
h1.put("hi2",20);
h1.put("hi3",10);
h1.put("hi4",20);
HashMap <String, Integer> h2;
h2.put("hi", 20);
h2.put("hi2", 20);
h2.put("hi3", 20);
h2.put("hi4", 20);
My question is, if I do the following
h2.putAll(h1);
How could I update the values of h2 to be the sum, instead of just overwriting it? That is I want
[{"hi"=50}]
[{"hi2"=40}]
[{"hi3"=30}]
[{"hi4"=40}]
Instead of this
[{"hi"=30}]
[{"hi2"=20}]
[{"hi3"=10}]
[{"hi4"=20}]
Note: no functional constructs (including lambdas) and external libraries are allowed
You can use merge method for that:
h1.forEach((key, value) -> h2.merge( key, value, Integer::sum));
System.out.println(h2);
The old fashion way:
for(String key : h1.keySet()){
Integer v1 = h1.get(key);
Integer v2 = h2.get(key);
h2.put(key, (v2 == null) ? v1 : v1 + v2);
}
System.out.println(h2);
In traditional Java (before functional constructs), you would just iterate over the map and get the values from the other map
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
for (Map.Entry<String, Integer> entry : h2.entrySet()) {
String key = entry.getKey();
Integer toAdd = h1.get(key);
if (toAdd != null) {
entry.setValue(entry.getValue() + toAdd);
}
}
System.out.println("h1 = " + h1);
System.out.println("h2 = " + h2);
Which prints
h1 = {hi=30}
h2 = {hi=50}
To go further, if the expected result should be that h2 should also contain every non-matching key from h1, then you can use the following
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
h1.put("hii", 40);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
for (Map.Entry<String, Integer> entry : h1.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
Integer toPossiblyMerge = h2.get(key);
if (toPossiblyMerge == null) {
h2.put(key, value);
} else {
h2.put(key, value + toPossiblyMerge);
}
}
System.out.println("h1 = " + h1);
System.out.println("h2 = " + h2);
Which prints
h1 = {hi=30, hii=40}
h2 = {hi=50, hii=40}
You can merge the two maps as shown below:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
Map<String, Integer> h3 = new HashMap<>(h1);
h2.forEach(
(key, value) -> h3.merge(key, value, (v1, v2) -> v1 + v2)
);
System.out.println(h3);
}
}
Output:
{hi=50}
Non-Lambda solution:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class Main {
public static void main(String[] args) {
Map<String, Integer> h1 = new HashMap<>();
h1.put("hi", 30);
Map<String, Integer> h2 = new HashMap<>();
h2.put("hi", 20);
Map<String, Integer> h3 = new HashMap<>(h1);
for (Entry<String, Integer> entry : h2.entrySet()) {
String key = entry.getKey();
h3.put(key, entry.getValue() + h1.getOrDefault(key, 0));
}
System.out.println(h3);
}
}
Output:
{hi=50}

Flatten nested Map containing with unknown level of nested Arrays and Maps recursively

I have a nested HashMap with String keys that contains either List, Map, or String values. I would like to flatten them like the below.
Here is the data:
import java.util.*;
import java.util.stream.*;
public class MyClass {
public static void main(String args[]) {
Map<String, Object> dates = new HashMap<String, Object>() {{
put("1999", new HashMap<String, Object>() {{
put("3", Arrays.asList("23", "24", "25"));
put("4", Arrays.asList("1", "2", "3"));
}});
put("2001", new HashMap<String, Object>() {{
put("11", new HashMap<String, Object>() {{
put("7", Arrays.asList("23", "24", "25"));
put("9", Arrays.asList("1", "2", "3"));
}});
put("12", "45");
}});
}};
System.out.println(dates);
}
}
Map looks like:
{2001={11={7=[23, 24, 25], 9=[1, 2, 3]}, 12=45},
1999={3=[23, 24, 25], 4=[1, 2, 3]}}
The flattening of map should look like this:
{2001.11.7.1=23, 2001.11.7.2=24, 2001.11.7.3=25, 2001.11.9.1=1, 2001.11.9.2=2,
2001.11.9.3=3, 2001.12=45, 1999.3.1=23, 1999.3.2=24, 1999.3.3=25,
1999.4.1=1, 1999.4.2=2, 1999.4.3=3}
Note: the level of nested arrays or maps is unknown, it may go more than 2 levels.
You can use recursion to flatten the Map. Each time you encounter a Map, recurse by flattening that Map; when you encounter a List, iterate over it and add the index to the current key. A single value can be trivially set otherwise. See the below code in action here.
public static Map<String, Object> flatten(final Map<String, Object> map) {
return flatten("", map, new HashMap<>());
//use new TreeMap<>() to order map based on key
}
#SuppressWarnings("unchecked")//recursive helper method
private static Map<String, Object> flatten(final String key, final Map<String, Object> map,
final Map<String, Object> result) {
final Set<Map.Entry<String, Object>> entries = map.entrySet();
if (!entries.isEmpty()) {
for (final Map.Entry<String, Object> entry : entries) {
//iterate over entries
final String currKey = key + (key.isEmpty() ? "" : '.') + entry.getKey();
//append current key to previous key, adding a dot if the previous key was not an empty String
final Object value = entry.getValue();
if (value instanceof Map) {//current value is a Map
flatten(currKey, (Map<String, Object>) value, result);//flatten Map
} else if (value instanceof List) {//current value is a List
final List<Object> list = (List<Object>) value;
for (int i = 0, size = list.size(); i < size; i++) {
result.put(currKey + '.' + (i + 1), list.get(i));
}
//iterate over the List and append the index to the current key when setting value
} else {
result.put(currKey, value);//set normal value
}
}
}
return result;
}
public static void main(final String[] args){
final Map<String, Object> flattened = flatten(dates);
System.out.println(flattened);
}
You can iterate over this map, and process each entry value, depending on its instance of: Map, List, or String. Since the level of nested arrays or maps is unknown, I have modified a little your code example and flat map format for clarity, also I used TreeMap instead of HashMap for entries ordering.
public static void main(String[] args) {
TreeMap<String, Object> treeMap = new TreeMap<String, Object>() {{
put("1999", new TreeMap<String, Object>() {{
put("3", Arrays.asList("23", "24", "25"));
put("4", Arrays.asList("1", "2", new TreeMap<String, Object>() {{
put("10", "42");
}}));
}});
put("2001", new TreeMap<String, Object>() {{
put("11", new TreeMap<String, Object>() {{
put("7", Arrays.asList("23", "24", "25"));
put("9", Arrays.asList("1", "2", "3"));
}});
put("12", "45");
}});
}};
TreeMap<String, String> flatMap = new TreeMap<>();
processMap("", treeMap, flatMap);
System.out.println(treeMap);
System.out.println(flatMap);
}
private static void processMap(String prefix,
Map<String, Object> map,
Map<String, String> flatMap) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
processEntry(prefix, key, value, flatMap);
}
}
private static void processList(String prefix,
List<Object> list,
Map<String, String> flatMap) {
for (int i = 0; i < list.size(); i++) {
String key = String.valueOf(i + 1);
Object value = list.get(i);
processEntry(prefix, key, value, flatMap);
}
}
#SuppressWarnings("unchecked")
private static void processEntry(String prefix,
String key,
Object value,
Map<String, String> flatMap) {
if (value instanceof Map) {
processMap(prefix + key + ".", (Map<String, Object>) value, flatMap);
} else if (value instanceof List) {
processList(prefix + key + ":", (List<Object>) value, flatMap);
} else if (value instanceof String) {
flatMap.put(prefix + key, (String) value);
}
}
Sample map:
{1999={3=[23, 24, 25], 4=[1, 2, {10=42}]},
2001={11={7=[23, 24, 25], 9=[1, 2, 3]}, 12=45}}
Flattened map:
{1999.3:1=23, 1999.3:2=24, 1999.3:3=25, 1999.4:1=1, 1999.4:2=2, 1999.4:3.10=42,
2001.11.7:1=23, 2001.11.7:2=24, 2001.11.7:3=25,
2001.11.9:1=1, 2001.11.9:2=2, 2001.11.9:3=3, 2001.12=45}
Opposite: Restoring a value tree from its flat map representation.
private static Map<String, String> flatten(Map<String, Object> m) {
var pairs = new ArrayList<String[]>();
flatten(null, m, pairs);
return pairs.stream().collect(Collectors.toMap(x -> x[0], x -> x[1]));
}
private static void flatten(String prefix, Map<String, Object> m, List<String[]> pairs) {
for (var e : m.entrySet()) {
var k = e.getKey();
var o = m.get(k);
if (o instanceof String s) {
pairs.add(new String[]{makeKey(prefix, k), s});
} else if (o instanceof List l) {
IntStream.range(0, l.size())
.mapToObj(i -> new String[]{
makeKey(prefix, k + "." + (i +1)),
l.get(i).toString()
})
.forEach(p -> pairs.add(p));
} else if (o instanceof Map nestedMap) {
flatten(makeKey(prefix, k), nestedMap, pairs);
}
}
}
private static String makeKey(String prefix, String key) {
return String.join(".", prefix == null ? List.of(key) : List.of(prefix,key));
}

Hashmap within ArrayList in Java

There is a hash map within the ArrayList. the output is like below
[{A=2},{A=3},{B=1},{B=4},{A=3}]
Below I have mentioned my code sample
ArrayList<Map<String, Short>> deviceInfo = new ArrayList<>();
Map<String, Integer> rssiMapper = new HashMap<>();
rssiMapper.put(device.getName(), rssi);
deviceInfo.add(rssiMapper);
I want to take mean value of A and B separately. How can I achieve that
Try it like this.
List<Map<String,Integer>> list = List.of(
Map.of("A", 2),
Map.of("A", 3),
Map.of("B", 1),
Map.of("B", 4),
Map.of("A", 3));
Map<String, Double> avgs = list.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(
Entry::getKey,
Collectors.averagingInt(Entry::getValue)));
System.out.println(avgs);
Prints
{A=2.6666666666666665, B=2.5}
As was suggested, if you are unfamiliar with streams, here is an iterative approach.
Map<String,Double> avgs = new HashMap<>();
Map<String,Integer> count = new HashMap<>();
for (Map<String,Integer> map : list) {
for (Entry<String,Integer> e : map.entrySet()) {
String key = e.getKey();
int value = e.getValue();
// These just either initialize or update the appropriate
// values.
avgs.compute(key, (k,v)-> v == null ? value : v + value);
count.compute(key, (k,v)->v == null ? 1 : v + 1);
}
}
// now find the averages.
for(Entry<String,Double> e : avgs.entrySet()) {
avgs.computeIfPresent(e.getKey(), (k,v)->v/count.get(e.getKey()));
}
System.out.println(avgs);
You can create maps to track the sum, count and the mean (i.e. sum / count) of the entries as shown below:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class Main {
public static void main(String[] args) {
List<Map<String, Integer>> list = List.of(Map.of("A", 2), Map.of("A", 3), Map.of("B", 1), Map.of("B", 4),
Map.of("A", 3));
Map<String, Integer> sumMap = new HashMap<>();
Map<String, Integer> countMap = new HashMap<>();
Map<String, Double> meanMap = new HashMap<>();
for (Map<String, Integer> map : list) {
for (Entry<String, Integer> entry : map.entrySet()) {
sumMap.put(entry.getKey(), sumMap.getOrDefault(entry.getKey(), 0) + entry.getValue());
countMap.put(entry.getKey(), countMap.getOrDefault(entry.getKey(), 0) + 1);
meanMap.put(entry.getKey(),
(double) sumMap.getOrDefault(entry.getKey(), 0) / countMap.getOrDefault(entry.getKey(), 1));
}
}
// Display
System.out.println(meanMap);
}
}
Output:
{A=2.6666666666666665, B=2.5}

How to flatten an array of dictionaries in Java?

I am working on below problem where I need to flatten array of dicts:
For example- Below is an input:
[
{'a':
{'b':
{'c':
{'d':'e'}
}
}
},
{'a':{'b':{'c':{'d':{'e':'f'}}}}},
{'a':'b'}
]
And the output will be:
[
{'a_b_c_d':'e'},
{'a_b_c_d_e':'f'},
{'a':'b'}
]
Below is what I was able to come up with. Is there any better way to solve this problem?
private static List<Map<String, String>> flatDictionary(final List<Map<String, Object>> input) {
List<Map<String, String>> listHolder = new ArrayList<>();
if(input == null || input.isEmpty()) {
return listHolder;
}
for(Map<String, Object> mapHolder : input) {
Map<String, String> m = new HashMap<>();
StringBuilder sb = new StringBuilder();
Map<String, String> output = helper(mapHolder, sb, m);
listHolder.add(output);
}
return listHolder;
}
private static Map<String, String> helper(final Map<String, Object> map, final StringBuilder sb, final Map<String, String> output) {
String mapValue = null;
for(Map.Entry<String, Object> holder : map.entrySet()) {
String key = holder.getKey();
Object value = holder.getValue();
if(value instanceof Map) {
sb.append(key).append("_");
helper((HashMap<String, Object>) value, sb, output);
} else if(value instanceof String) {
sb.append(key);
mapValue = (String) value;
}
output.put(sb.toString(), mapValue);
}
return output;
}
I would use recursion.
First define a method to flatten a single Map
public static void flatten(final String keyPrefix, final Map<String, Object> input, final Map<String, Object> output) {
for (final Map.Entry<String, Object> e : input.entrySet()) {
final var key = keyPrefix.isBlank() ? e.getKey() : keyPrefix + "_" + e.getKey();
if (e.getValue() instanceof Map) {
// if the nested Map is of the wrong type bad things may happen
flatten(key, (Map<String, Object>) e.getValue(), output);
} else {
output.put(key, e.getValue());
}
}
}
NB: This makes no attempt to deal with duplicate keys.
Usage:
public static void main(final String[] args) throws InterruptedException {
final var data = Map.of(
"A", Map.of("a", "Expect A_a"),
"B", Map.of("b1", Map.of(
"bb1", "expect B_b1_bb1",
"bb2", "expect B_b1_bb2"
)),
"C", "Expect C");
final var output = new HashMap<String, Object>();
flatten("", data, output);
output.forEach((k, v) -> System.out.printf("%s -> %s%n", k, v));
}
Output:
C -> Expect C
A_a -> Expect A_a
B_b1_bb2 -> expect B_b1_bb2
B_b1_bb1 -> expect B_b1_bb1
Now, simply define a method that loops to take your List
public static final Map<String, Object> flattenAll(final List<Map<String, Object>> input) {
final var output = new HashMap<String, Object>();
input.forEach(map -> flatten("", map, output));
return output;
}
NB: This makes no attempt to deal with duplicate keys.

Java streams sum values of a List of Maps

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");
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));
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
}
}
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());
This gives the same answer even after changing the values
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);

Categories

Resources