【问题标题】:Count in single pass multiple items using java 8 stream使用 java 8 流计算单遍多个项目
【发布时间】:2016-08-05 13:36:50
【问题描述】:

假设我有以下课程:

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++
    }
 }

可以像简单地使用流一样完成吗?

【问题讨论】:

    标签: java java-stream


    【解决方案1】:

    您可以通过为总计创建一个收集器来做到这一点:

    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);
    

    与迭代解决方案相比,这具有优势,您可以使流并行,如果您的列表非常大,这可能具有性能优势。

    【讨论】:

    • 谢谢!当您需要并行性时,这非常简洁。我习惯于认为 Steam.collect() 主要与收藏有关。您向我展示了它可以用于更广泛的背景。
    【解决方案2】:

    你可以使用我发在this answermultiClassify收集器:

    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 等常用输入的性能而言通常还不错。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多