如何将多个 predicate 应用于java.util.Stream's
filter()
方法?
这就是我现在做的,但我真的不喜欢它。我有一个Collection
的东西,我需要减少基于Collection
的过滤器( predicate )的东西的数量:
Collection<Thing> things = someGenerator.someMethod();
List<Thing> filtered = things.parallelStream().filter(p -> {
for (Filter f : filtersCollection) {
if (f.test(p))
return true;
}
return false;
}).collect(Collectors.toList());
我知道,如果我事先知道过滤器的数量,我可以做这样的事情:
List<Thing> filtered = things.parallelStream().filter(filter1).or(filter2).or(filter3)).collect(Collectors.toList());
但是,如何在不混合编程风格的情况下应用未知数量的 predicate 呢?现在,它看起来有点丑…
4条答案
按热度按时间67up9zun1#
如果你有一个
Collection<Predicate<T>> filters
,你总是可以使用名为 reduction 的过程来创建一个 predicate :或
这取决于你想如何合并过滤器。
如果
orElse
调用中指定的空 predicate 集合的回退满足标识角色(x->true
对and
执行的操作,x->false
对or
执行的操作)您也可以使用reduce(x->true, Predicate::and)
或reduce(x->false, Predicate::or)
来获取过滤器,但这会导致对于非常小的集合,它的效率稍低,因为它总是将标识 predicate 与集合的 predicate 组合在一起,即使它只包含一个 predicate 。相比之下,如果集合的大小为1
,则上面显示的变体reduce(accumulator).orElse(fallback)
将返回单个 predicate 。请注意,此模式也适用于类似的问题:有了一个
Collection<Consumer<T>>
,您可以使用以下命令创建一个Consumer<T>
等等。
k2arahey2#
我假设你的
Filter
是一个不同于java.util.function.Predicate
的类型,这意味着它需要适应它。一种可行的方法是这样的:这会导致为每个 predicate 计算重新创建过滤器流的轻微性能下降。为了避免这种情况,您可以将每个过滤器 Package 成一个
Predicate
并将它们组合起来:然而,由于现在每个过滤器都在其自己的
Predicate
之后,引入了一个间接级别,因此不清楚哪种方法会具有更好的整体性能。如果不考虑适应性(如果你的
Filter
恰好是Predicate
),问题陈述会变得简单得多,第二种方法显然获胜:kt06eoxx3#
我已经设法解决了这样一个问题,如果用户想要在一个过滤操作中应用一个 predicate 列表,一个可以是动态的并且不给定的列表,那么应该减少到一个 predicate -像这样:
注意,这将把它们与一个“AND”逻辑运算符组合在一起。要与“OR”合并,减少线应该是:
3pvhb19x4#
这是解决这个问题的一个有趣的方法,(直接从http://www.leveluplunch.com/java/tutorials/006-how-to-filter-arraylist-stream-java8/粘贴)。我认为这是一种更有效的方法。
编辑:这里是如何处理循环,其中predicatesToIgnore是一个 predicate 列表。我从它创建一个 predicate predicate ToIgnore。
然后,用这个 predicate 进行过滤。这创造了一个更好的过滤IMHO