在Java中对流过滤器函数进行优先级排序
我正在寻找一个选项,以过滤流,但使用优先级 以下是伪代码:在Java中对流过滤器函数进行优先级排序,java,java-8,java-stream,Java,Java 8,Java Stream,我正在寻找一个选项,以过滤流,但使用优先级 以下是伪代码: results.stream().filter(prio1).ifNotFound(filter(prio2)).collect(toList()) 结果列表应按照称为“prio1”的第一个标准进行过滤,如果没有找到匹配项,则应使用第二个过滤器尝试对称为prio2的第二个标准进行过滤,然后收集结果 如何在Java8中使用流实现这一点 我正在寻找一艘顺流而下的班轮。只需提出一个条件: final List<Foo> foo;
results.stream().filter(prio1).ifNotFound(filter(prio2)).collect(toList())
结果列表应按照称为“prio1
”的第一个标准进行过滤,如果没有找到匹配项,则应使用第二个过滤器尝试对称为prio2
的第二个标准进行过滤,然后收集结果
如何在Java8中使用流实现这一点
我正在寻找一艘顺流而下的班轮。只需提出一个条件:
final List<Foo> foo;
if (results.stream().anyMatch(prio1)) {
foo = results.stream().filter(prio1).collect(Collectors.toList());
} else {
foo = results.stream().filter(prio2).collect(Collectors.toList());
}
您将需要对结果执行两次
stream()
,但以下内容应作为一行:
results.stream().filter(results.stream().anyMatch(prio1) ? prio1 : prio2).collect(Collectors.toList());
(由于首次使用类似策略发布多行程序,这要归功于。)
编辑:由于一些优秀的新答案已经曝光,我想我会参考此线程的某些其他部分,为这种多流/anyMatch
策略提供一个简短的辩护:
- ,
优化为提前返回,因此读取额外流的时间最短(特别是对于anyMatch
可能匹配的情况)。事实上,prio1
在回退(anyMatch
)情况下将只读取整个流,因此对于平均运行,您只需迭代一个分数的列表长度prio2
- 使用
方法在每种情况下构造一个映射和两个列表,而上述方法最多只创建一个列表。随着Collectors.groupingBy(…)
大小的增加,内存开销的差异将变得非常显著。对整个流进行分组,因此即使第一个元素恰好通过结果
,每个元素都必须根据prio1
进行检查,然后再根据prio1.或(prio2)
进行检查prio1
不考虑groupingBy
和prio1
不相互排斥的情况。如果通过prio2
的部分prio2.test(e)
可以返回e
,则回退true
列表中将缺少此类元素。每次使用prio2
和一个过滤器可以避免此问题anyMatch
- 对我来说,上述方法的行长度和复杂性似乎更易于管理
Optional.of(results.stream()
.filter(prio1.or(prio2))
.collect(Collectors.groupingBy(prio1::test)))
.map(map -> map.getOrDefault(true, map.get(false)))
.ifPresent(System.out::println);
我使用了Optional
,这样您就有了一个“一行程序”(只是格式化了它,以便它更具可读性)。您也可以使用orelsget(Collections::emptyList)
将结果保存到列表中,而不是ifPresent
将prio1
和prio2
筛选条目中的所有prio1
匹配条目放入键true
,其余prio2
匹配条目放入false
。如果true
中没有任何条目,那么prio2
过滤的条目将作为默认值返回。如果没有任何prio1
或prio2
匹配结果,则不会发生任何情况
请注意,如果您直接返回映射
,那么如果您的过滤器互斥,则在false
中只有所有prio2
匹配条目。不清楚您所说的ifNotFound
是什么意思。您能说第二个过滤器prio2在哪种情况下不适用吗?所有项目都应是第一个与prio1匹配,如果未找到,则再次将所有项目与PRIO2匹配。它应为一个衬里。。。不,如果你可以通过把条件映射到一个属性,使它成为一个单行程序,但是我不认为有一个单行程序比上面的条件更好(否:anyMatch经过优化,它将提前返回,这对于prio1可能出现的情况很好。有没有办法将其写入一行中,而不需要多次迭代?@Ckkn鉴于要求,我会说没有。您可以重写它,为一次迭代构建两个列表,但是,这会增加内存消耗。记住,两次运行线性时间复杂度运算的sO(n)
仍然是O(n)
.ie)O(2n)=O(n)
正在构思一个想法。我在手机上,请稍候:)好的,下面解释一下为什么您必须多次流式传输结果。检查prio1
是否应用于列表的至少一个元素是“终端操作”,这意味着流不再可用。如果prio1
匹配成功,可以避免两次流式传输列表,但这需要相当长的行:Optional.of(results.stream().filter(prio1.collector.toList()).filter(list->!list.isEmpty()).orElseGet(()->results.stream().filter(prio2.collector.toList())
(希望我没有错过那里的任何参数!)@Ckkn如果你足够绝望,这是可能的:results.stream().filter(prio1.or(prio2)).collect(Collectors.partitionby(prio1)).entrySet().stream().sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()).Map(Map.Entry::getValue).filter(list->!list.isEmpty()).findFirst().orElse(Collections.emptyList());
@shmosel不过你不必那么绝望;-)我想有人会想出这样一个聪明的解决方案……多谢你花了这么多时间!从技术上讲,你调用了两次stream
。这很酷!聪明地使用了groupingBy
。谢谢你教我一些新东西:)非常好,比我的黑客好多了。很遗憾,您不能使用partitioningBy()
。map()
函数有点不必要的聪明.map(map->map.getOrDefault(true,map.get(false))
在功能和性能上是等效的,只是稍微长一点,而且可读性更好,依我看。@shmosel您也可以
Optional.of(results.stream()
.filter(prio1.or(prio2))
.collect(Collectors.groupingBy(prio1::test)))
.map(map -> map.getOrDefault(true, map.get(false)))
.ifPresent(System.out::println);