我正在寻找一个过滤流内容但使用优先级的选项。
以下是伪代码:
results.stream().filter(prio1).ifNotFound(filter(prio2)).collect(toList())
结果列表应按照名为" prio1
"的第一个标准进行过滤。如果找不到匹配项,则应使用第二个过滤器尝试过滤第二个标准prio2
,然后收集结果
如何使用流在Java 8中实现此目的?
我正在寻找一个单行流。
答案 0 :(得分:4)
另一种不使用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
,因此你有一个"一个班轮" (只是格式化它,以便它更具可读性)。您也可以使用ifPresent
而不是orElseGet(Collections::emptyList)
,而将结果保存到List<String>
。
groupingBy
将prio1
和prio1
个过滤条目中的所有prio2
个匹配条目放入密钥true
和其余prio2
- 匹配false
条目。如果我们没有true
中的任何条目,那么prio2
- 已过滤的条目将作为默认值返回。如果没有任何prio1
或prio2
匹配结果,则不会发生任何事情。
请注意,如果您直接返回Map
,那么如果您的过滤器是互斥的,则只有prio2
中的所有false
个匹配条目。
答案 1 :(得分:3)
您需要stream()
两次您的搜索结果,但以下内容应该作为一行:
results.stream().filter(results.stream().anyMatch(prio1) ? prio1 : prio2).collect(Collectors.toList());
(感谢flakes首先使用类似的策略发布多个班轮。)
编辑:由于一些出色的新答案已经曝光,我想我会对这种多流/ anyMatch
策略进行简短的辩护,并参考其中的某些其他部分螺纹:
As pointed out by eckes,anyMatch
已经过优化,可以提前返回,从而花费最少的时间来阅读额外的流(特别是在prio1
可能匹配的情况下)。事实上,anyMatch
只会在后备(prio2
)情况下读取整个流,因此对于平均运行,您只是迭代一个和一个分数列表长度。
在每种情况下,使用Collectors.groupingBy(...)
方法构造一个Map和两个Lists,而上面的方法最多只创建一个List。随着results
的大小增加,这里的内存开销差异将变得非常显着。分组是针对整个流完成的,因此即使第一个元素恰好通过prio1
,也必须针对prio1.or(prio2)
检查每个元素,然后针对{{1>检查再一次。
prio1
未考虑groupingBy
和prio1
不相互排斥的情况。如果prio2
可以为通过prio2.test(e)
的某些true
返回e
,那么这些元素将在后备prio1
列表中丢失。一次使用prio2
和一个过滤器可以避免此问题。
上述方法的行长和复杂性对我来说似乎更容易管理。
答案 2 :(得分:2)
只是提出一个条件:
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());
}
如果你真的想要一个单行,那么你可以做以下事情,但是没有办法绕过两次列表。我认为if/else
版本更清晰,更易于维护。
final List<Foo> foo = results.stream()
.filter(results.stream().anyMatch(prio1)? prio1 : prio2)
.collect(Collectors.toList());