有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

是否可以简单地使用流来实现


共 (2) 个答案

  1. # 1 楼答案

    您可以使用我在this answer中发布的multiClassify收集器:

    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这样的常用输入,在性能方面通常不是很差

  2. # 2 楼答案

    您可以通过为总计创建收集器来完成此操作:

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

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