Java 如果前一个筛选器导致空流,则对原始流进行筛选

Java 如果前一个筛选器导致空流,则对原始流进行筛选,java,java-stream,Java,Java Stream,正在寻找一种方法,如果以前的过滤器返回空流,则在原始流上应用过滤器。例如: 给定一系列数字 获取并返回所有偶数 如果没有,则获取并返回所有3的倍数 如果没有,则获取并返回所有5的倍数 等等 一个简单的方法是: List<Integer> numbers = ... List<Integer> filteredNums = numbers.stream() .filter(n -> n % 2 == 0) .collect(Collectors.

正在寻找一种方法,如果以前的过滤器返回空流,则在原始流上应用过滤器。例如:

  • 给定一系列数字
  • 获取并返回所有偶数
  • 如果没有,则获取并返回所有3的倍数
  • 如果没有,则获取并返回所有5的倍数
  • 等等
一个简单的方法是:

List<Integer> numbers = ...

List<Integer> filteredNums = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());

if (filteredNums.isEmpty()) {
    filteredNums = numbers.stream()
        .filter(n -> n % 3 == 0)
        .collect(Collectors.toList());
}

if (filteredNums.isEmpty()) {
    filteredNums = numbers.stream()
        .filter(n -> n % 5 == 0)
        .collect(Collectors.toList());
}
列表编号=。。。
List filteredNums=numbers.stream()
.filter(n->n%2==0)
.collect(Collectors.toList());
if(filteredNums.isEmpty()){
filteredNums=numbers.stream()
.filter(n->n%3==0)
.collect(Collectors.toList());
}
if(filteredNums.isEmpty()){
filteredNums=numbers.stream()
.filter(n->n%5==0)
.collect(Collectors.toList());
}
给定一个数字列表,如1,3,5,15,21,将得到3,15,21


我的数字示例是我试图做的一个简化版本,但传达了相同的概念。我可以创建一个收集器来完成这项工作,但总的来说,我觉得我缺少一些简单的东西。理想情况下,我希望该解决方案能够在流中使用,以便我可以继续对其执行其他流操作。在这种情况下,我可能希望将其简化为一个求和或映射,其中我将每个数字相乘,然后收集到一个列表中。

这里有一种方法,您可以组合您的条件:

List<Integer> divs = Arrays.asList(2, 3, 5);
List<Integer> filteredNums = divs.stream()
        .filter(d -> numbers.stream().anyMatch(n -> n % d == 0))
        .findFirst()
        .map(d -> numbers.stream().filter(n -> n % d == 0).collect(Collectors.toList()))
        .orElse(Collections.EMPTY_LIST);
List divs=Arrays.asList(2,3,5);
List filteredNums=divs.stream()
.filter(d->numbers.stream().anyMatch(n->n%d==0))
.findFirst()
.map(d->numbers.stream().filter(n->n%d==0).collect(collector.toList())
.orElse(集合。空列表);


其思想是使用您想要使用的除法器创建一个列表,然后找到第一个除法器(如果有),然后过滤所有数字或返回一个空列表

您可以拥有一个包含谓词的流,并使用每个谓词过滤集合,直到过滤操作的结果返回一个非空列表:

Stream<Predicate<Integer>> predicates = Stream.of(n -> n % 2 == 0,
                                                  n -> n % 3 == 0,
                                                  n -> n % 5 == 0);

List<Integer> filteredNums = predicates.map(
        predicate -> numbers.filter(predicate)
                            .collect(Collectors.toList()))
    .dropWhile(Collection::isEmpty)
    .findFirst()
    .orElse(Collections.emptyList());
Stream谓词=Stream.of(n->n%2==0,
n->n%3==0,
n->n%5==0);
List filteredNums=predicates.map(
谓词->数字.过滤器(谓词)
.collect(收集器.toList())
.dropWhile(集合::isEmpty)
.findFirst()
.orElse(Collections.emptyList());
这会将每个谓词转换为过滤列表(通过将当前谓词应用于原始列表)。筛选后的空列表将被删除,直到谓词生成非空列表或谓词全部被使用。

list predicates=Arrays.asList(n->n%2==0,
List<Predicate<Integer>> predicates = Arrays.asList(n -> n % 2 == 0,
            n -> n % 3 == 0,
            n -> n % 5 == 0);

    List<Integer> numbers = Arrays.asList(11,12,15,4,43);

    List<Integer> integers = predicates.stream()
            .map(p -> numbers.stream().filter(n -> p.test(n)).collect(Collectors.toList()))
            .filter(l -> !l.isEmpty())
            .findFirst().orElse(Collections.emptyList());
n->n%3==0, n->n%5==0); 列表编号=数组.asList(11,12,15,4,43); 列表整数=谓词。流() .map(p->numbers.stream().filter(n->p.test(n)).collect(collector.toList()) .filter(l->!l.isEmpty()) .findFirst().orElse(Collections.emptyList());
肯定会适用于我的具体示例,尽管我在最初的问题中应该更清楚。我只是用这个例子来保持简单。过滤器谓词是更改的内容。我的实际用例是,我通过流式处理对象,找到与特定过滤器匹配的所有对象,如果没有找到,则转到下一个过滤器。我想我可以做一些类似于您所做的事情,但顶部的列表可能是一个谓词列表。@SteveW这是正确的,您可以在原始问题中传递一个谓词列表。也许这可以改进为不将每个谓词的数字流两次divisor@fps如果只有一个流和一个收集,这将是理想的。这个答案和你提供的答案是目前为止最好的。这两种方法乍一看都不太容易理解,但它们回答了问题,并且很容易扩展到我提供的示例之外。很好的解决方案!为什么不直接将
.orElse(Collections.emptyList())
标记到
findFirst()
并返回实际的
列表
@WJS当然,为什么不呢?谢谢你的建议我想知道什么更好,在主流中流一次,然后收集像你一样的每一个,或者流两次,然后收集一次,就像YCF_L的解决方案一样。同样重要的是要注意dropWhile来自Java9。我发现有趣的是,很多人对Java9甚至11的特性提出警告,就好像在我们已经达到Java14的时候,它是新的东西一样。然而,我不记得在Java 1.5中发布泛型之后,关于泛型的警告级别有多高。从Java 8开始,有一个很大的区别,版本更频繁,直到大约11个版本才引入主要的新功能,所以人们会跳过版本。此外,许多较大的公司采用速度较慢,可能只支持某个特定版本。