根据以前的计算结果停止java流计算

时间:2017-09-12 10:05:41

标签: java java-8 java-stream

如何根据以前的结果打破流计算?如果很明显stream.filter(...)。count()会小于某个数字 - 如何停止流计算?

我有以下代码检查某些sampleData是否通过predicate测试:

// sampleData.size() may be greater than 10.000.000
Set<String> sampleData = downloadFromWeb(); 
return sampleData.stream().filter(predicate::test).count() > sampleData.size() * coefficient;

我可以有数千sampleData。问题是这段代码无效。例如,如果coefficient等于0.5sampleData.size() = 10_000_000和第一个5_000_000元素未通过predicate::test - 则没有理由验证上一个5_000_000元素( count()永远不会大于5_000_000 )。

3 个答案:

答案 0 :(得分:4)

说实话,我不太确定这是否正确,我希望有人会来回顾一下,但这是我使用自定义分裂器的想法:

 static class CustomSpl<T> extends AbstractSpliterator<T> {

    private Spliterator<T> source;

    private int howMany;

    private int coefficient;

    private Predicate<T> predicate;

    private T current;

    private long initialSize;

    private void setT(T t) {
        this.current = t;
    }

    public CustomSpl(Spliterator<T> source, int howMany, int coefficient, Predicate<T> predicate, long initialSize) {
        super(source.estimateSize(), source.characteristics());
        this.source = source;
        this.howMany = howMany;
        this.coefficient = coefficient;
        this.predicate = predicate;
        this.initialSize = initialSize;
    }

    @Override
    public boolean tryAdvance(Consumer<? super T> action) {
        boolean hasMore = source.tryAdvance(this::setT);

        System.out.println(current);

        if (!hasMore) {
            return false;
        }

        if (predicate.test(current)) {
            ++howMany;
        }

        if (initialSize - howMany <= coefficient) {
            return false;
        }

        action.accept(current);
        return true;
    }

}

例如,这只会产生4个元素,因为我们只关心有一个系数5

Spliterator<Integer> sp = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).stream().spliterator();

long count = StreamSupport.stream(new CustomSpl<>(sp, 0, 5, x -> x > 3, sp.getExactSizeIfKnown()), false)
            .count();

这也适用于只有已知尺寸的分裂器。

答案 1 :(得分:4)

ZhekaKozlov’s answer正朝着正确的方向前进,但缺乏否定。对于大于特定阈值的匹配,非匹配元素的数量必须小于“大小 - 阈值”。如果我们测试不匹配的元素是否更小,我们可以应用limit一旦它们变大就停止:

Set<String> sampleData = downloadFromWeb();
final long threshold = sampleData.size()-(long)(sampleData.size() * coefficient);
return sampleData.stream()
                 .filter(predicate.negate()).limit(threshold+1).count() < threshold;

顺便说一句,没有理由创建对Predicate的现有predicate::test的测试方法的方法引用,例如Predicate。只需将filter传递给predicate.negate()方法即可。上面的代码也使用predicate.negate()::test代替pug ...

答案 2 :(得分:0)

Max Chars