2016-08-05 50 views
2

單程多個項目假設我有下面的類:計數在用java 8流

class Z { 
    X x; 
    Y y; 
} 

我有Z元素的列表。我想統計一下在x字段中有多少元素的值爲x1,y字段中有多少元素的值爲y1。

使用循環是直截了當:

int countOfx1 = 0; 
int countOfy1 = 0; 
for (Z z: list) { 
    if (z.x == x1) { 
     countOfx1++ 
    } 
    if (z.y == y1) { 
     countOfy1++ 
    } 
} 

能不能做到簡單地使用流?

回答

4

您可以通過創建總計收集器做到這一點:

class Zcount { 
    private int xCount = 0; 
    private int yCount = 0; 

    public Zcount accept(Z z) { 
     if (z.x == x1) 
      xCount++; 
     if (z.y == y1) 
      yCount++; 
     return this; 
    } 

    public Zcount combine(ZCount other) { 
     xCount += other.xCount; 
     yCount += other.yCount; 
     return this; 
    } 
} 

Zcount count = list.stream().collect(Zcount::new, Zcount::accept, Zcount::combine); 

這樣做的好處在迭代的解決方案,可以使數據流並行可能有性能上的優勢,如果你的列表是非常大的。

+0

謝謝!當你需要並行時,這非常整齊。我習慣在Steam.collect()上思考,主要是關於Collections。你向我展示了它可以用於更廣泛的環境。 – Shay

2

可以使用multiClassify集電極我張貼在this answer

List<Predicates> preds = Arrays.asList(z -> z.x == x1, z -> z.y == y1); 
List<Long> counts = stream.collect(multiClassify(preds, Collectors.counting())); 
// counts.get(0) -> counts for z.x == x1 
// counts.get(1) -> counts for z.y == y1 

的簡單的替代方法是,當然,遍歷輸入兩次:

long countsX = list.stream().filter(z -> z.x == x1).count(); 
long countsY = list.stream().filter(z -> z.y == y1).count(); 

這樣的解決方案是短且通常不對於像ArrayList這樣的常用輸入來說性能很差。