Lambda 使用Java8流在两个列表上迭代
如何在Java8流中编写以下内容Lambda 使用Java8流在两个列表上迭代,lambda,java-8,java-stream,Lambda,Java 8,Java Stream,如何在Java8流中编写以下内容 int total = 0; for (ObjectA obja : rootObj.getListA()) { for (ObjectB objb : obja.getListB()) { total += objb.getCount() * obja.getCount(); } } return total; 相当简单:将ObjectA映射到其所有ObjectB::getCount的总和乘以其自身的getCoun
int total = 0;
for (ObjectA obja : rootObj.getListA()) {
for (ObjectB objb : obja.getListB()) {
total += objb.getCount() * obja.getCount();
}
}
return total;
相当简单:将
ObjectA
映射到其所有ObjectB::getCount
的总和乘以其自身的getCount()
,然后简单地将IntStream
相加:
int total = rootObj.getListA().stream()
.mapToInt(obja -> obja.getCount() * obja.getListB().stream().mapToInt(ObjectB::getCount).sum())
.sum();
为了提高可读性,您可以引入私有助手方法:
int total = rootObj.getListA().stream()
.mapToInt(this::calculate)
.sum();
private int calculate(ObjectA obja) {
return obja.getListB().stream()
.mapToInt(ObjectB::getCount)
.sum() * obja.getCount();
}
使用助手方法:
int total = rootObj.getListA().stream()
.mapToInt(this::calculate)
.sum();
private int calculate(ObjectA obja) {
return obja.getListB().stream()
.mapToInt(ObjectB::getCount)
.sum() * obja.getCount();
}
以下是一个在许多情况下可能更可取的替代解决方案:
int total = rootObj.getListA().stream()
.flatMapToInt(objA -> objA.getListB()
.stream().mapToInt(objB -> objB.getCount() * objA.getCount()))
.sum();
将循环的嵌套
转换为流
API用法的标准解决方案是通过flatMap
:
return rootObj.getListA().stream()
.flatMapToInt(objA->objA.getListB().stream()
.mapToInt(objB->objB.getCount() * objA.getCount()))
.sum();
这允许您为每个内部迭代执行一个操作。但是,在求和的特殊情况下,您可以简化操作,因为无论您是计算(a+b+c+d)
还是(a+b)+(c+d)
:
当我们在记忆基本算术时,我们还应该记得,(a*x)+(b*x)
等于(a+b)*x
,换句话说,没有必要将列表b
的每一项与objA
的计数相乘,因为我们也可以将结果与该计数相乘:
return rootObj.getListA().stream()
.mapToInt(objA->objA.getListB().stream().mapToInt(ObjectB::getCount).sum()*objA.getCount())
.sum();
对于同时行走两条溪流的更一般的解决方案,这不是一个很好的解决方案,但它是一个有效的解决方案
public static <A, B, C> Stream<C> zip(
Stream<A> a,
Stream<B> b,
BiFunction<A, B, C> op) {
Iterator<A> i1 = a.iterator();
Iterator<B> i2 = b.iterator();
Iterable<C> i = () -> new Iterator<C>() {
@Override
public boolean hasNext() {
return i1.hasNext() && i2.hasNext();
}
@Override
public C next() {
return op.apply(i1.next(), i2.next());
}
};
// Not certain whether we can do this in parallel - probably not.
return StreamSupport.stream(i.spliterator(), false);
}
publicstaticstreamzip(
a流,
b流,
双功能(op){
迭代器i1=a.Iterator();
迭代器i2=b.迭代器();
Iterable i=()->新迭代器(){
@凌驾
公共布尔hasNext(){
返回i1.hasNext()&&i2.hasNext();
}
@凌驾
公共C next(){
返回op.apply(i1.next(),i2.next());
}
};
//不确定我们是否能同时做到这一点——也许不能。
返回StreamSupport.stream(i.spliterator(),false);
}
这不是OP想要的。您正在同步迭代两个流,而作者希望为listA的每个值迭代listB列表的所有值。您的版本是“点积”,而OP想要的是“交叉积”。@TagirValeev-这是真的-但这个答案适用于使用Java 8流在两个列表上迭代的问题标题。使用flatMapToInt替代mapToInt有什么区别?mapToInt
将每个元素转换为另一个元素,而flatMapToInt
将单个元素转换为多个元素的序列。