How to sum values โ€‹โ€‹inside nested foreach loops?

How to sum the sum using stream api with nested foreach loops where everyone 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 sne foreach loop:

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

How can I integrate the snd foreach loop into the first to get the global sum of nested lists?

+5
source share
4 answers

You can 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 am not sure if this break; intends in your source code.


Using the break; statement break; It should look 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 check whether it is valid, then you map each FirstNode to its SndNode , for which you will find the first one that has the type NodeType.AMOUNT . Then you need to filter to get only optional options that are not empty, and for them you get the SndNode in which they are contained, for which you get the corresponding amount.

+8
source

Your attempt is approaching the right decision.

 response.getFirstNodes().stream() .filter(FirstNode::isValid) .mapToDouble(first -> first.getSndNodes().stream() .filter(snd -> snd.getType() == NodeType.AMOUNT) .mapToDouble(snd -> snd.getAmount()) .findAny().orElse(0)) .sum(); 

If you are sure that there is no more than one match in the internal thread, you can use findAny , since then there is no order requirement. I used the simplest solution to solve the problem of a possible lack of correspondence, replacing it with 0 , which is transparent to sum and will save us from additional filtering.

+4
source

You can use flatMap to create a single stream of all internal lists:

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

You can use .flatMap() nested nodes. For instance:

 response.getFirstNodes().stream() .filter(FirstNode::isValid) .flatMap(first -> first.getSndNodes().stream()) .filter(snd -> snd.getType == NodeType.AMOUNT) .mapToDouble(SndNode::getAmount) .sum(); 
+2
source

Source: https://habr.com/ru/post/1216082/


All Articles