简体   繁体   English

如何使用Lambda表达式减少给定列表.reduce()方法

[英]How to reduce given list by using Lambda expression .reduce() method

List<Integer> integers = Arrays.asList(1, 2, 3, 5, 6, 8, 9, 10);
integers.stream().filter((integer) -> integer % 2 == 0).collect(Collectors.toList());

As shown above integers is a List, from which we need to filter only even numbers. 如上所示, integers是一个List,我们只需要过滤偶数。 I can achieve by using .filter() method. 我可以通过使用.filter()方法来实现。 But, is there any possibility to achieve the same with .reduce() method. 但是,有没有可能用.reduce()方法实现相同的功能。 Hope, .reduce() method filtered out all the other elements by performing given BynaryOperation and return reduced list. 希望, .reduce()方法通过执行给定的BynaryOperation并返回简化列表来过滤掉所有其他元素。

If my understanding is not correct on .reduce() method, please let me know what exactly this method do. 如果我对.reduce()方法的理解不正确,请告诉我这个方法究竟是做什么的。

Your understanding of reduction is wrong. 你对减少的理解是错误的。 reduce will apply a function on all elements repeatedly to get one single result . reduce将重复对所有元素应用函数以获得单个结果

You seem to think of reduce like doing 你似乎认为减少就像做

1, 2, 3, 5, 6, 8, 9, 10
│  │  │  │  │  │  │  │
└op┘  └op┘  └op┘  └op┘
  │     │     │     │
    result list

whereas, in fact, it does 事实上,确实如此

1, 2, 3, 5, 6, 8, 9, 10
│  │  │  │  │  │  │  │
└op┘  └op┘  └op┘  └op┘
  │    │      │    │
  └─op─┘      └─op─┘
     │          │
     └────op────┘
           │
   final result value

Though, this is a conceptional view, the exact order of operations is unspecified. 虽然这是一个概念视图,但未指定操作的确切顺序。 A sequential execution will be like (((1 op 2) op 3) op 4)… while a parallel execution will be a mixture of an execution like the tree above and partial sequential execution(s). 顺序执行将类似于(((1 op 2) op 3) op 4)…而并行执行将是执行的混合,如上面的树和部分顺序执行。


You can abuse reduce to create a result list if you first convert each element into a List and then use a list operation which concatenates each list, however, there are two problems with this: 如果首先将每个元素转换为List ,然后使用连接每个列表的列表操作,则可以滥用reduce来创建结果列表,但是,这有两个问题:

  • It doesn't provide the desired “skip each second element (of the original list)” logic; 它没有提供所需的“跳过每个第二个元素(原始列表)”的逻辑; if you look at the tree above, it should become clear, that it is impossible to formulate a correct op function which does that in every possible execution scenario 如果你看一下上面的树,它应该变得清楚,在每个可能的执行场景中都不可能形成一个正确的op函数。
  • creating temporary lists and concatenating them is very inefficient 创建临时列表并连接它们是非常低效的

The latter point can be solved by using collect , which is a mutable reduction, hence, allows you to use mutable lists to which you can add items, however, it does not address the first point, including the desired filter would violate the contract and only work in a sequential execution. 后一点可以通过使用collect来解决,这是一个可变的减少,因此,允许您使用可添加项目的可变列表,但是,它没有解决第一点,包括所需的过滤器会违反合同和仅适用于顺序执行。

So the solution is to define a filter for all elements in the scope of the source list, followed by a mutable reduction to create the result list using collect , and, big surprise, that's exactly what you original code does: 所以解决方案是为源列表范围内的所有元素定义一个filter ,然后使用collect创建结果列表的可变缩减,并且,大惊喜,这正是您原始代码的作用:

… .filter(integer -> integer % 2 == 0).collect(Collectors.toList());

You can use the Stream.reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner) method, which takes three parameters: 您可以使用Stream.reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)方法,该方法有三个参数:

  • identity : The identity element is both the initial value of the reduction and the default result if there are no elements in the stream. identity :如果流中没有元素,则identity元素既是减少的初始值又是默认结果。 In your case, it will be an empty list . 在您的情况下,它将是一个空列表
  • accumulator : The accumulator function takes two parameters: a partial result of the reduction and the next element of the stream (in this example, an integer). accumulator :accumulator函数有两个参数:reduce的部分结果和stream的下一个元素(在本例中为整数)。 It applies a check for modulo 2 and then returns a new partial result. 它对模2应用检查,然后返回新的部分结果。
  • combiner : It's purpose is to combine the internal temporary collector-accumulators of the stream batches that are being processes in parallel. 组合器 :它的目的是组合并行处理的流批次的内部临时收集器 - 累加器。

For example: 例如:

BinaryOperator<ArrayList<Integer>> combiner = (x, y) -> { x.addAll(y); return x; };
BiFunction<ArrayList<Integer>, Integer, ArrayList<Integer>> accumulator = (x, y) -> {
    if (y % 2 == 0) {
        x.add(y);
    }
    return x;
};
List<Integer> list = Stream.of(1, 2, 3, 5, 6, 8, 9, 10).reduce(new ArrayList<Integer>(),
                                                               accumulator,
                                                               combiner);
System.out.println(list);

Note that this solution may not work for parallel Streams. 请注意,此解决方案可能不适用于并行Streams。 Also, it's way too easier to stick to the .filter() approach, so I strongly advice you to do so. 另外,坚持使用.filter()方法太容易了,所以我强烈建议你这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM