Let’s say I have the following list.
List<StringInteger> test = new ArrayList<>(); //StringInteger is just a pojo with String and int
test.add(new StringInteger("a", 1));
test.add(new StringInteger("b", 1));
test.add(new StringInteger("a", 3));
test.add(new StringInteger("c", 1));
test.add(new StringInteger("a", 1));
test.add(new StringInteger("c", -1));
System.out.println(test); //[{ a : 1 }, { b : 1 }, { a : 3 }, { c : 1 }, { a : 1 }, { c : -1 }]
I need to write a method that would unite items by String key and add integers. So that the result list would be [{ a : 5 }, { b : 1 }, { c : 0 }]
I could do it using HashMap, but if I go that way – I’ll have to create a Map, then use foreach with if(containsKey(...)) and then convert it back to List. It just seems like an overkill.
Is there more elegant solution? I thought that flatMap from Stream API should do the thing, but I cannot figure out how.
UPD:
Here’s my clumsy solution. It works, but I believe that it can be done more simple than that.
Map<String, Integer> map = new HashMap<>();
for (StringInteger stringInteger : test) {
if (map.containsKey(stringInteger.getKey())) {
int previousValue = map.get(stringInteger.getKey());
map.put(stringInteger.getKey(), previousValue + stringInteger.getValue());
} else {
map.put(stringInteger.getKey(), stringInteger.getValue());
}
}
List<StringInteger> result = map.entrySet().stream().map(stringIntegerEntry -> new StringInteger(stringIntegerEntry.getKey(), stringIntegerEntry.getValue())).collect(Collectors.toList());
System.out.println(result); //[{ a : 5 }, { b : 1 }, { c : 0 }]
>Solution :
As @Louis Wasserman said in the comment HashMap is the right tool for this task.
To translate the hole code into a stream, you can use the built-in collector groupingBy() in conjunction with summingInt as the downstream collector grouping.
result = test.stream()
.collect(Collectors.groupingBy( // creates an intermediate map Map<String, Integer>
StringInteger::getKey, // mapping a key
Collectors.summingInt(StringInteger::getValue) // generating a value
))
.entrySet().stream()
.map(entry -> new StringInteger(entry.getKey(), entry.getValue()))
.toList();