Lambda 使用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

如何在Java8流中编写以下内容

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
将单个元素转换为多个元素的序列。