如何对嵌套的 foreach 循环中的值求和?
How to sum values within nested foreach loops?
如何使用 stream
api 和嵌套的 foreach 循环(每个循环都有一个过滤条件)计算总和?
//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 循环集成到第一个循环中,以获得嵌套列表的全局总和?
您可以使用 flatMap 创建所有内部列表的单个流:
response.getFirstNodes()
.stream()
.filter (first -> first.isValid())
.flatMap (first -> first.getSndNodes().stream())
.filter(snd -> snd.getType() == NodeType.AMOUNT)
.mapToDouble(snd -> snd.getAmount())
.sum();
您可以使用 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
。然后,您需要过滤以仅获取不为空的 Optionals,对于它们,您将获得 SndNode
它们包含的相应数量。
您可以使用 .flatMap()
嵌套节点。例如:
response.getFirstNodes().stream()
.filter(FirstNode::isValid)
.flatMap(first -> first.getSndNodes().stream())
.filter(snd -> snd.getType == NodeType.AMOUNT)
.mapToDouble(SndNode::getAmount)
.sum();
您的尝试接近于正确的解决方案
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
是透明的,并且使我们免于额外的过滤。
如何使用 stream
api 和嵌套的 foreach 循环(每个循环都有一个过滤条件)计算总和?
//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 循环集成到第一个循环中,以获得嵌套列表的全局总和?
您可以使用 flatMap 创建所有内部列表的单个流:
response.getFirstNodes()
.stream()
.filter (first -> first.isValid())
.flatMap (first -> first.getSndNodes().stream())
.filter(snd -> snd.getType() == NodeType.AMOUNT)
.mapToDouble(snd -> snd.getAmount())
.sum();
您可以使用 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
。然后,您需要过滤以仅获取不为空的 Optionals,对于它们,您将获得 SndNode
它们包含的相应数量。
您可以使用 .flatMap()
嵌套节点。例如:
response.getFirstNodes().stream()
.filter(FirstNode::isValid)
.flatMap(first -> first.getSndNodes().stream())
.filter(snd -> snd.getType == NodeType.AMOUNT)
.mapToDouble(SndNode::getAmount)
.sum();
您的尝试接近于正确的解决方案
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
是透明的,并且使我们免于额外的过滤。