I have a simple pojo:
class Pojo
{
string key;
int value;
}
This is in a list:
List<Pojo> myList;
I can have multiple values per key, so for example:
A 5
A 7
B 3
So I want to group by the key and sum the values and put it back into a List<Pojo>
with a single entry for A 12, B 3, etc.
This is what I have right now:
myMap.get("xxx")
.values()
.stream()
.collect(Collectors.groupingBy(Pojo::getKey), Collectors.summingLong(Pojo::getValue))
This gets me a Map<String, Int>
.
Do I need to do something like:
myMap.get("xxx")
.values()
.stream()
.collect(Collectors.groupingBy(Pojo::getKey), Collectors.summingLong(Pojo::getValue))
.entrySet().stream.map((entry) -> new Pojo(..)).collect(Collectors.toList())
Or is there a cleaner way to do it?
It should work when using Collectors::reducing
.
myMap.get("xxx").values().stream()
.collect(Collectors.groupingBy(Pojo::getKey, Collectors.reducing(
new Pojo(null, 0),
(a, b) -> new Pojo(b.getKey(), a.getValue() + b.getValue())))
.values()
The call to groupingBy
would return a Map<String, List<Pojo>>
, but providing a reducing collector as second argument to groupingBy
takes the values of the list and reduces them to a single element. The result is a Map<String, Pojo>
, and in order to get a Collection<Pojo>
, we simply need to call values()
on the Map
.
There are several ways to do it. Sometimes the simplest is the best and most efficient. Here is one of them.
List<Pojo> list = List.of(new Pojo("A", 5), new Pojo("B", 3),
new Pojo("A", 7), new Pojo("C", 10), new Pojo("B", 12));
Map<String, Pojo> map = new HashMap<>();
The way this works is as follows:
for (Pojo p : list) {
Pojo cp;
if ((cp = map.get(p.getKey())) != null) {
cp.setValue(cp.getValue() + p.getValue());
} else {
map.put(p.getKey(), p);
}
}
This next step could be eliminated if you don't mind working with type Collection
.
List<Pojo> results = new ArrayList<>(map.values());
Now print them
results.forEach(Sytem.out::println);
Prints
A 12
B 15
C 10
On the other hand, if you prefer streams this works sans a setter. But it does create a new object to replace the old one.
Map<String, Pojo> map = list.stream()
.collect(Collectors.toMap(Pojo::getKey, s -> s,
(a, b) -> new Pojo(a.getKey(),
a.getValue() + b.getValue())));
map.values().forEach(Sytem.out::println);
The pojo class
class Pojo { String key; int value;
public Pojo(String key, int value) {
this.key = key;
this.value = value;
}
public int getValue() {
return value;
}
public String getKey() {
return key;
}
public void setValue(int v) {
this.value = v;
}
public String toString() {
return key + " " + value;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.