2015-05-20 24 views
3

如何在Java 8流中編寫以下內容?使用Java 8流遍歷兩個列表

int total = 0; 
    for (ObjectA obja : rootObj.getListA()) { 
    for (ObjectB objb : obja.getListB()) { 
     total += objb.getCount() * obja.getCount(); 
    } 
    } 

return total; 

回答

2

相當容易:地圖ObjectA到的所有ObjectB::getCount乘以自身的getCount(),然後簡單地總結了IntStream總和:

int total = rootObj.getListA().stream() 
    .mapToInt(obja -> obja.getCount() * obja.getListB().stream().mapToInt(ObjectB::getCount).sum()) 
    .sum(); 

爲了提高可讀性,你可以引入一個私有helper方法:

int total = rootObj.getListA().stream() 
    .mapToInt(this::calculate) 
    .sum(); 

用輔助方法:

private int calculate(ObjectA obja) { 
    return obja.getListB().stream() 
      .mapToInt(ObjectB::getCount) 
      .sum() * obja.getCount(); 
} 
3

下面是一個替代的解決方案,其可能在一些情況下是優選的:

int total = rootObj.getListA().stream() 
    .flatMapToInt(objA -> objA.getListB() 
     .stream().mapToInt(objB -> objB.getCount() * objA.getCount())) 
    .sum(); 
+1

使用mapToInt的flatMapToInt insdead有什麼區別? – jliakos

+2

'mapToInt'將每個元素轉換爲另一個元素,而'flatMapToInt'則將單個元素轉換爲多個元素的序列。 –

4

用於轉換嵌套for循環來Stream 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)的特殊情況:

return rootObj.getListA().stream() 
.mapToInt(objA->objA.getListB().stream() 
           .mapToInt(objB->objB.getCount() * objA.getCount()).sum()) 
.sum(); 

而且當我們在記住基本的算術我們也應該記得,(a*x)+(b*x)等於(a+b)*x,換句話說,是沒有必要的ListB每個項目乘以的objA算作我們也可以只是多與計數相加結果:

return rootObj.getListA().stream() 
.mapToInt(objA->objA.getListB().stream().mapToInt(ObjectB::getCount).sum()*objA.getCount()) 
.sum(); 
2

而對於更廣泛的解決方案一次走兩條流這是不是很好,但它的工作原理的解決方案。

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); 
} 
+2

這不是OP想要的。您正在同步迭代兩個流,並且作者想要爲listA的每個值迭代listB列表的所有值。你的版本是「點積」,而OP想要一個「跨產品」。 –

+0

@TagirValeev - 這是真的 - 但這個答案適用於問題標題*使用Java 8流*迭代兩個列表。 – OldCurmudgeon