Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Summing multiple different fields in a list of objects using the streams api?

Tags:

java

java-8

In Java 8, if I have a list of Objects like this:

 MyObject
   double a;
   double b;
   double c;

I want to get the totals of each of these fields in the list of objects. One way I can to do it, is as follows:

double totalA = myListOfObjects.stream().map(e -> e.getA()).reduce(0.0, (x, y) -> x + y);
double totalB = myListOfObjects.stream().map(e -> e.getB()).reduce(0.0, (x, y) -> x + y);
double totalC = myListOfObjects.stream().map(e -> e.getC()).reduce(0.0, (x, y) -> x + y);  

But is there away to combine this into one pass through the list of objects usng the streams api? If I just wrote a for/while loop (see below) and manually added up the 3 totals, that would seem more efficent then the above 3 lines of code)

for (MyObject obj: myListOfObjects) {
    totalA += obj.getA();
    totalB += obj.getB();
    totalC += obj.getC();
}

Thanks

like image 360
Pat Avatar asked Oct 14 '16 09:10

Pat


1 Answers

You can reduce into new MyObject objects like this:

MyObject totals = myListOfObjects.stream()
    .reduce((x, y) -> new MyObject(
        x.getA() + y.getA(),
        x.getB() + y.getB(),
        x.getC() + y.getC()
    ))
    .orElse(new MyObject(0, 0, 0));

totalA = totals.getA();
totalB = totals.getB();
totalC = totals.getC();

Anyway, I don't think you should worry about performance here. All three solutions (2 in your question + mine above) have O(n) time complexity. I would recommend doing some reading about premature optimisations. Just go for the code which is most readable and the easiest to understand.

You could also extract the code to sum two objects into a method in MyObject class:

public class MyObject {

    // fields, constructors, getters etc.

    public MyObject sum(MyObject other) {
        return new MyObject(
                this.a + other.a,
                this.b + other.b,
                this.c + other.c
        );
    }
}

This would allow you to use a method reference: .reduce(MyObject::sum)

like image 199
Jaroslaw Pawlak Avatar answered Sep 20 '22 10:09

Jaroslaw Pawlak