Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sum each field in stream of objects

I want to create instance of object MyObject, each field of which will be sum of values of that field from

I create an object

       public class MyObject{
           int value;
           double length;
           float temperature;

           MyObject(int value, double length, float temperature){
               this.value = value;
               this.length = length
               this.temperature = temperature
           }
        }

Then I construct list of objects:

    List<MyObject> list = new ArrayList<MyObject>{{
          add(new MyObject(1, 1d, 1.0f));
          add(new MyObject(2, 2d, 2.0f));
          add(new MyObject(3, 3d, 3.0f));
    }}

I want create object (new MyObject(6, 6d, 6f))

It is easy to sum one field per stream:

Integer totalValue = myObjects.parallelStream().mapToInt(myObject -> myObject.getValue()).sum(); //returns 6;

or

Double totalLength = myObjects.parallelStream().mapToDouble(MyObject::getLength).sum(); //returns 6d

and then construct object new MyObject(totalValue, totalLength, totalTemperature);

But can I sum all fields in one stream? I want stream to return

new MyObject(6, 6d, 6.0f)
like image 967
addmeaning Avatar asked Mar 12 '23 08:03

addmeaning


2 Answers

The other solutions are valid, but they both incur unnecessary overhead; one by copying MyObject multiple times, the other by streaming the collection multiple times. If MyObject is mutable, the ideal solution would be a mutable reduction using collect():

// This is used as both the accumulator and combiner,
// since MyObject is both the element type and result type
BiConsumer<MyObject, MyObject> reducer = (o1, o2) -> {
    o1.setValue(o1.getValue() + o2.getValue());
    o1.setLength(o1.getLength() + o2.getLength());
    o1.setTemperature(o1.getTemperature() + o2.getTemperature());
}
MyObject totals = list.stream()
        .collect(() -> new MyObject(0, 0d, 0f), reducer, reducer);

This solution only creates a single additional MyObject instance, and only iterates the list once.

like image 187
shmosel Avatar answered Mar 21 '23 07:03

shmosel


It is a direct application for reduce method:

Stream.of(new MyObject(1, 1d, 1.0f), new MyObject(2, 2d, 2.0f), new MyObject(3, 3d, 3.0f)).
                reduce((a, b) -> new MyObject(a.value + b.value, a.length + b.length, a.temperature + b.temperature))
like image 34
featuredpeow Avatar answered Mar 21 '23 07:03

featuredpeow