1

I want to summarize the attributes of my objects. The objects have a structure like this:

class Foo{
   String name;
   int = price;
   int = fees;
   //etc
}

I have collected them into a List and want to get (with streams) a list of all elements that only contain the name and the sum of the price and fees. For example:

{name=Apple, price=2; fees=1}
{name=Potato, price=7, fees=10}
{name=strawberry, price=5, fees=4}

should lead to this result:

{name=Apple, sum=3}
{name=Potato, sum=17}
{name=strawberry, sum=9}
gerli
  • 13
  • 3

2 Answers2

0
Map<String, Integer> result = 
foos.stream()
    .collect(
        Collectors.groupingBy(
            Foo::getName, 
            Collectors.summingInt(x -> x.getPrice() + x.getFees())
        )
);

collect to a Map with a Collectors::groupingBy and a downstream collector : Collectors::summingInt.

Or you can use toMap:

foos.stream()
    .collect(
        Collectors.toMap(
               Foo::getName,
               x -> x.getPrice() + x.getFees(),
               Integer::sum
        )
    );

This is rather easy to achieve if you just read the documentation a bit.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • Thank you for your answer. It helped me a lot. To be honest I read the doc, but couldn't really understand it. So I'm glad you 'explained' it like this. I thought that if I'm using .summingInt it'll only sum the values of one special field and not that you can sum like this – gerli Jan 25 '21 at 19:08
0

Implement class Bar:

class Bar {
    String name;
    int sum;

    // mapping constructor
    public Bar(Foo foo) {
        this.name = foo.name;
        this.sum = foo.price + foo.fees;
    }
}

and remap Foo using reference to the constructor:

List<Bar> sums = listFoos.stream().map(Bar::new).collect(Collectors.toList());

Instead of constructor a method with the same functionality may be implemented.


If multiple instances of Foo need to be summarized into single Bar, a method to merge a Bar may be added to Bar:

class Bar {
// ...
    public Bar merge(Bar bar) {
        this.sum += bar.sum;
        return this;
    }
}

Then the collection of Bar can be retrieved as values of the following map:

Collection<Bar> sumBars = listFoos
    .stream()
    .collect(Collectors.toMap(Foo::getName, Bar::new, Bar::merge))
    .values();
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42