Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Lambda Multiple operations on a single stream

Tags:

java

lambda

Scenario: I have a object with 2 functions -->

<Integer> getA(); <Integer> getB();

I have a list of objects, say List<MyObject> myObject.

Objective Iterate over the List and get sum of A and B's in the List of object.

My Solution

myObject.stream().map(a -> a.getA()).collect(Collectors.summingDouble());

myObject.stream().map(a -> a.getB()).collect(Collectors.summingDouble());

The Question: How can I do both of these at the same time? This way I will not have to iterate twice over the original list.

@Edit: I was doing this because some of the filters that I used were of O(n^3). Kind of really bad to do those twice.

Benchmark : It really matters if it is T or 2T when the program runs for half hour on an i5. This was on much lesser data and if I run on a cluster, my data would be larger too.

It does matter if you can do these in one line!.

like image 657
Pranay Avatar asked Oct 19 '22 03:10

Pranay


1 Answers

You need to write another class to store the total values like this:

public class Total {
    private int totalA = 0;
    private int totalB = 0;

    public void addA(int a) {
        totalA += a;
    }

    public void addB(int b) {
        totalB += b;
    }

    public int getTotalA() {
        return totalA;
    }

    public int getTotalB() {
        return totalB;
    }
}

And then collect the values using

Total total = objects.stream()
        .map(o -> (A) o)
        .collect(Total::new,
                (t, a) -> {
                    t.addA(a.getA());
                    t.addB(a.getB());
                },
                (t1, t2) -> { });
//check total.getTotalA() and total.getTotalB()

You can also use AbstractMap.SimpleEntry<Integer, Integer> to replace Total to avoid writing a new class, but it's still kind of weird because A/B are not in a key-value relationship.

like image 150
Cheng Chen Avatar answered Nov 02 '22 06:11

Cheng Chen