在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鉴于要求,我会说没有。您可以重写它,为一次迭代构建两个列表,但是,这会增加内存消耗。记住,两次运行线性时间复杂度运算的s
O(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);