Search code examples
javaforeachjava-8java-stream

Stream equivalent of summing values within nested foreach loops with a filter


How can a sum be calculated using the Stream API with nested foreach loops where each has a filter condition?

//java7
Double sum = null; 
for (FirstNode first : response.getFirstNodes()) {
    if (first.isValid()) {
        for (SndNnode snd : first.getSndNodes()) {
            if (snd.getType() == NodeType.AMOUNT) {
                sum += snd.getAmount();
                break;
            }
        }
    }
}

//java8
response.getFirstNodes().stream().filter(first -> first.isValid()).mapToDouble(???).sum();

My snd foreach loop would be:

first.getSndNodes().stream().filter(snd -> snd.getType() == NodeType.AMOUNT).mapToDouble(snd -> snd.getAmount()).findFirst().sum();

How could I now integrate the snd foreach loop into the first, to get a global sum of the nested lists?


Solution

  • You could use flatMap:

    response.getFirstNodes()
            .stream()
            .filter(first -> first.isValid())
            .flatMap(first -> first.getSndNodes().stream())
            .filter(snd -> snd.getType() == NodeType.AMOUNT)
            .mapToDouble(snd -> snd.getAmount())
            .sum();
    

    I'm not sure whether that break; is intentional in your original code.


    With the break; statement, it should looks like this:

    response.getFirstNodes()
                    .stream()
                    .filter(first -> first.isValid())
                    .map(first -> first.getSndNodes().stream().filter(snd -> snd.getType() == NodeType.AMOUNT).findFirst())
                    .filter(Optional::isPresent)
                    .mapToDouble(opt -> opt.get().getAmount())
                    .sum();
    

    Basically, for each FirstNode you test whether it's valid, then you map each FirstNode to a stream of its SndNodes for which you find the first that has the type NodeType.AMOUNT. You need then to filter to get only Optionals that are not empty and for them you get the SndNode they contains for which you get the corresponding amount.