在一个流中进行多个“匹配”检查

2022-09-04 20:08:11

是否可以检查数组(或集合)是否包含元素 5 5 以外的元素。在一个返回布尔结果的流中,而不是使用两个流:

int[] ints = new int[]{1, 2, 3, 4, 5};

boolean hasFive = IntStream.of(ints).anyMatch(num -> num == 5);
boolean hasNonFive = IntStream.of(ints).anyMatch(num -> num != 5);

boolean result = hasFive && hasNonFive;

答案 1

这里有两个涉及我的StreamEx库的解决方案。我在这里使用的核心功能是短路集电极的概念。我的库增强了概念,以提供短路能力(适用于顺序流和并行流)Collector

如果谓词与样本中类似(一个与另一个相反),则可以使用 :partitioningBy

Map<Boolean, Optional<Integer>> map = IntStreamEx.of(ints).boxed()
        .partitioningBy(num -> num == 5, MoreCollectors.first());

现在,您应该检查两个映射是否存在:

System.out.println(map.values().stream().allMatch(Optional::isPresent));

或在单个语句中:

System.out.println(IntStreamEx.of(ints).boxed()
        .partitioningBy(num -> num == 5, MoreCollectors.first())
        .values().stream().allMatch(Optional::isPresent));

在这里,我们使用MoreCollectors.first()短路收集器。此解决方案类似于@user140547提出的解决方案,但一旦找到两个元素,它实际上将停止处理。


对于两个自定义谓词,可以使用配对收集器,它将两个收集器的结果组合在一起(如果输入收集器短路,则保留短路)。但首先,我们需要收集器(在我的库中没有):anyMatching

import static one.util.streamex.MoreCollectors.*;

static <T> Collector<T, ?, Boolean> anyMatching(Predicate<T> pred) {
    return collectingAndThen(filtering(pred, first()), Optional::isPresent);
}

Collector<Integer, ?, Boolean> hasFive = anyMatching(num -> num == 5); 
Collector<Integer, ?, Boolean> hasNonFive =  anyMatching(num -> num != 5);
Collector<Integer, ?, Boolean> hasBoth = pairing(hasFive, hasNonFive, 
          (res1, res2) -> res1 && res2);

System.out.println(IntStreamEx.of(ints).boxed().collect(hasBoth));

答案 2

在这种特定情况下,即您想知道流或数组是否同时包含匹配和不匹配元素(与谓词的否定匹配的元素),您可以更简单地做到这一点。

首先,测试第一个元素是否与谓词或其否定匹配,然后,搜索流是否包含任何相反的匹配项:

IntPredicate predicate=i -> i==5;

if(ints.length>0 && predicate.test(ints[0]))
    predicate=predicate.negate();
boolean result = IntStream.of(ints).anyMatch(predicate);

就是这样。如果您没有数组或集合作为流源,而是任意流,则测试第一个元素会有点棘手:

IntPredicate[] tmp={ null };
Spliterator.OfInt sp=intStream.spliterator();
boolean result = sp.tryAdvance(
    (int i) -> tmp[0]=predicate.test(i)? predicate.negate(): predicate)
 && StreamSupport.intStream(sp, false).anyMatch(tmp[0]);

推荐