2

I have a list of GroupItem objects:

public class GroupItem {
    Group group;
    BigDecimal value;
    ...
}

What I want to achieve is a Map where value for the same Group key is aggregated. I implemented it in the following way (slightly refactored variant, but still far from being elegant):

List<GroupItem> items = generateGroupItemList();

Map<Group, BigDecimal> resultMap = new HashMap<>();
    for (GroupItem item : items) {
        resultMap.put(item.getGroup(), resultMap.getOrDefault(item.getGroup(), BigDecimal.ZERO).add(item.getValue()));
    }

This variant looks ugly and lacks readability. I tried using streams, but didn't achieve any positive result. The general idea was around Collectors.groupingBy() and something like this:

items.stream().collect(
        Collectors.groupingBy(
                GroupItem::getGroup,
                Collectors.reducing(GroupItem:getValue, /*BigDecimal::add*/)
));

Is there more elegant way to achieve desired effect, besides the variant above?

Naman
  • 27,789
  • 26
  • 218
  • 353
Dragon
  • 2,431
  • 11
  • 42
  • 68
  • Just to remind me: [Replacing `groupingBy` and `reducing` by `toMap`](https://stackoverflow.com/questions/57041896/java-streams-replacing-groupingby-and-reducing-by-tomap) you can achieve it as in [this answer](https://stackoverflow.com/a/58882379/1746118). – Naman Nov 15 '19 at 18:04

2 Answers2

2

You can use merge method:

  List<GroupItem> items = generateGroupItemList();

  Map<Group, BigDecimal> resultMap = new HashMap<>();
  for (GroupItem item : items) {
    resultMap.merge(item.getGroup(), item.getValue(), BigDecimal::add);
  }
Alex Filatov
  • 4,768
  • 2
  • 16
  • 10
  • I changed the example in the question to be one-line and less ugly, but still far from being ideal. And your answer makes it perfect. Thank you. – Dragon Nov 15 '19 at 17:52
2

Using Stream, you can perform toMap with Collectors:

Map<Group, BigDecimal> resultMap = items.stream()
        .collect(Collectors.toMap(GroupItem::getGroup,
                GroupItem::getValue, BigDecimal::add));
Naman
  • 27,789
  • 26
  • 218
  • 353
  • 2
    As a stream approach it is very compact and nice solution. I forgot that Collectors.toMap() has BinaryOperator arg for merging. – Dragon Nov 15 '19 at 18:02