在原始流上进行筛选,如果先前的筛选导致流为空,则返回。

huangapple go评论74阅读模式
英文:

Filter on original stream if previous filter resulted in an empty stream

问题

寻求一种方法,在原始流上应用过滤器,如果先前的过滤器返回了空流,则进行操作。例如:

  • 给定一串数字
  • 获取并返回所有偶数
  • 如果没有偶数,获取并返回所有能被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());
}

对于给定的数字列表,如1、3、5、15、21,将得到3、15、21。

我的数字示例是我尝试做的事情的简化版本,但传达了相同的概念。我可以创建一个Collector来实现这一点,但总的来说,我觉得有些简单的东西我可能忽略了。理想情况下,我希望解决方案能够在流中使用,以便我可以继续对其执行其他流操作。在这种情况下,也许我想将其缩减为一个和,或者映射,其中我将每个数字都相乘,然后收集到一个列表中。

英文:

Looking to come up with a way to apply a filter on the original stream if a previous filter returned an empty stream. For instance:

  • Given a stream of numbers
  • Get and return all even numbers
  • If none, get and return all numbers that are a multiple of 3
  • If none, get and return all numbers that are a multiple of 5
  • etc..

A trivial approach to this would be:

List&lt;Integer&gt; numbers = ...

List&lt;Integer&gt; filteredNums = numbers.stream()
    .filter(n -&gt; n % 2 == 0)
    .collect(Collectors.toList());

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

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

Given a list of numbers such as 1, 3, 5, 15, 21, would result in 3,15,21.

My example with numbers is a simplified version of what I'm trying to do, but conveys the same concept. I could create a Collector to do this, but in general I feel there is something simple I'm missing. Ideally I'd like the solution to be able to be used in a stream so I can continue performing additional stream operations on it. In this scenario, maybe I'd want to reduce it to a sum or map where I multiple each number and the collect into a list.

答案1

得分: 3

你可以使用流来处理谓词,并对集合进行过滤,直到过滤操作的结果返回一个非空列表:

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());

这将每个谓词转换为一个经过过滤的列表(通过将当前谓词应用于原始列表)。过滤后的空列表将被丢弃,直到某个谓词产生非空列表,或者所有谓词都被消耗完为止。

英文:

You could have a stream with your predicates and filter your collection with each one of them, until the result of the filter operation returns a non empty list:

Stream&lt;Predicate&lt;Integer&gt;&gt; predicates = Stream.of(n -&gt; n % 2 == 0,
                                                  n -&gt; n % 3 == 0,
                                                  n -&gt; n % 5 == 0);

List&lt;Integer&gt; filteredNums = predicates.map(
        predicate -&gt; numbers.filter(predicate)
                            .collect(Collectors.toList()))
    .dropWhile(Collection::isEmpty)
    .findFirst()
    .orElse(Collections.emptyList());

This transforms each predicate to a filtered list (by applying the current predicate to the original list). Filtered empty lists are dropped, until a predicate produces a non empty list or the predicates are all consumed.

答案2

得分: 2

以下是您可以将条件组合的方法:

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);

这个思路是创建一个包含您想要使用的除数的列表,然后找到第一个除数(如果存在),然后过滤所有满足条件的数字,否则返回一个空列表。

英文:

Here is a way where you can combine your conditions :

List&lt;Integer&gt; divs = Arrays.asList(2, 3, 5);
List&lt;Integer&gt; filteredNums = divs.stream()
        .filter(d -&gt; numbers.stream().anyMatch(n -&gt; n % d == 0))
        .findFirst()
        .map(d -&gt; numbers.stream().filter(n -&gt; n % d == 0).collect(Collectors.toList()))
        .orElse(Collections.EMPTY_LIST);

The idea is to create a list with the dividers that you want to use, and then find the first divider if it is present then filter all the numbers or return an Empty list

答案3

得分: 2

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());
英文:
List&lt;Predicate&lt;Integer&gt;&gt; predicates = Arrays.asList(n -&gt; n % 2 == 0,
            n -&gt; n % 3 == 0,
            n -&gt; n % 5 == 0);

    List&lt;Integer&gt; numbers = Arrays.asList(11,12,15,4,43);

    List&lt;Integer&gt; integers = predicates.stream()
            .map(p -&gt; numbers.stream().filter(n -&gt; p.test(n)).collect(Collectors.toList()))
            .filter(l -&gt; !l.isEmpty())
            .findFirst().orElse(Collections.emptyList());

huangapple
  • 本文由 发表于 2020年9月19日 02:42:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/63961194.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定