如何在嵌套的foreach循环中求和值?

时间:2015-03-25 12:18:50

标签: java foreach java-8 java-stream

如何使用带有嵌套foreach循环的stream api来计算总和,其中每个循环都有过滤条件?

//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();

我的foreach循环将是:

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

我现在如何将snd foreach循环集成到第一个循环中,以获得嵌套列表的全局总和?

4 个答案:

答案 0 :(得分:8)

您可以使用flatMap

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

我不确定原始代码中是否有意break;


使用break;语句,它应如下所示:

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();

基本上,对于每个FirstNode您测试它是否有效,然后您将每个FirstNode映射到其SndNode的流,您找到的第一个NodeType.AMOUNT类型SndNode。然后,您需要进行过滤以仅获取非空的Optionals,并为您获取它们包含的{{1}},您将获得相应的金额。

答案 1 :(得分:4)

您的尝试接近正确的解决方案

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();

如果您确定内部流中最多只有一个匹配项,则可以使用findAny,因为对订购没有要求。我使用最简单的解决方案来处理可能缺少匹配的问题,将其替换为对0透明的sum,并使我们免于额外过滤。

答案 2 :(得分:2)

您可以使用flatMap创建所有内部列表的单个Stream:

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

答案 3 :(得分:2)

您可以使用.flatMap()嵌套节点。例如:

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