代码之家  ›  专栏  ›  技术社区  ›  cahen

是否可以只迭代一次流并执行2个或更多操作?

  •  3
  • cahen  · 技术社区  · 9 年前

    给定代码

    List<Integer> numbers = Arrays.asList(2, 4, 3);
    
    int sumTotal = numbers.stream().reduce(-3, (x, y) -> x + y + 3);
    int multiplyTotal = numbers.stream().reduce(1, (x, y) -> x * y);
    

    是否可以在只迭代流一次的同时执行这两个操作?

    此外,请注意每个reduce都有不同的标识:-3和1。

    3 回复  |  直到 9 年前
        1
  •  4
  •   Community CDub    7 年前

    你可以使用我写的配对收集器 this answer :

    int[] result = numbers.stream().collect(
            pairing(
                    Collectors.reducing(0, (x, y) -> x + y + 3),
                    Collectors.reducing(1, (x, y) -> x * y),
                    (sum, prod) -> new int[] { sum, prod }));
    

    当然,您可以以任何其他方式组合结果。将它们放入数组只是一个示例。

    此收集器在我的 StreamEx 图书馆( MoreCollectors.pairing ). 或者,您可以使用jOOL库:它有 Tuple.collectors 该方法以类似的方式工作。

        2
  •  3
  •   JB Nizet    9 年前

    您可以创建自定义类,并使用可变缩减:

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(2, 4, 3);
    
        Result result = numbers.stream().collect(Result::new, Result::consume, Result::combine);
        System.out.println("result = " + result);
    }
    
    private static class Result {
        private int sum = 0;
        private int product = 1;
    
        public void consume(int i) {
            sum += i + 3;
            product *= i;
        }
    
        public void combine(Result r) {
            // READ note below
            sum += r.sum + 3;
            product *= r.product;
        }
    
        @Override
        public String toString() {
            return "Result{" +
                "sum=" + sum +
                ", product=" + product +
                '}';
        }
    }
    

    但我怀疑,通过重复两次迭代,你会从中获益匪浅。

    编辑:

    注意,上面的combine()方法在使用并行流时调用,将产生与顺序流不一致的结果。正如霍尔格在评论中提到的那样,问题的产生是因为操作不尊重归约的恒等前提条件:将归约应用于具有恒等式的任何值V,都会产生V,但它会产生具有0作为恒等式的V+3。

    确保不要使用并行流来计算该结果。

        3
  •  1
  •   U Avalos    9 年前

    在JS中,一种解决方案是迭代对象而不是数字。前任:

      numbers.stream().reduce({sum:0,prod:1}, (memo, cur) ->
           memo.sum = memo.sum + cur + 3;
           memo.prod = memo.prod * cur;
           return memo;
      )
    

    注意,在您的示例中, x 是“备忘录”(或累加器),并且 y 是当前值。

    同样的想法也适用于Java。