流相当于使用过滤器对嵌套 foreach 循环中的值进行求和

问题描述 投票:0回答:4

如何使用带有嵌套 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();

我的

snd
foreach 循环将是:

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

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

java foreach java-8 java-stream
4个回答
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
,您将获得相应的金额。


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
投票

您可以使用 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();

2
投票

您可以使用

.flatMap()
嵌套节点。例如:

response.getFirstNodes().stream()
                        .filter(FirstNode::isValid)
                        .flatMap(first -> first.getSndNodes().stream())
                        .filter(snd -> snd.getType == NodeType.AMOUNT)
                        .mapToDouble(SndNode::getAmount)
                        .sum();
© www.soinside.com 2019 - 2024. All rights reserved.