2017-09-12 16 views
8

以前の結果に基づいてストリーム計算を中断するにはどうすればよいですか? stream.filter(...)。count()がいくつかの数値より小さいことが明らかな場合 - ストリームの計算を停止する方法は?以前の計算結果に基づいてJavaストリームの計算を停止する

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

Iは、sampleData数千を有することができる:

は、私はいくつかsampleDatapredicate試験に合格するかどうかを確認する次のコードを有しています。問題は、このコードが効果がないことです。 coefficient0.5sampleData.size() = 10_000_000、最初5_000_000要素が等しい場合たとえば、predicate::test失敗した - 最後5_000_000要素を検証する理由はありません(数は()より大きく5_000_000なることはありません)。

+2

なぜforループを使用しないのでしょうか? Java 9は、必要な処理を行うStream :: takeWhileメソッドを提供します。 – daniu

+0

半分+ 1が真であればtrueを返し、半分+ 1が偽の場合はfalseを返しますか? – ByeBye

+0

@ByeBye半分より大きい場合は正確なカウントを返したいが、カウントが半分よりも小さい場合は何か他のものを返す –

答えて

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; 

ANの試験方法へのメソッドの参照を作成する理由は、方法によって、ありません既存のPredicatepredicate::testのようです。 Predicatefilterメソッドに渡すだけです。上記のコードでも、predicate.negate()::testの代わりにpredicate.negate()が使用されています。

+0

残念ながら、この解決策は短絡ではありません。例えば。 Set.of(1,2,3,4,5,6,7,8,9,10)に4未満の3つの要素が含まれていることをテストする場合は、10要素すべてをテストしますが、テストするだけでよい最初の3つの要素。この解決策は私の反対です。 – ZhekaKozlov

+0

@ZhekaKozlov: 'Set'には定義された順序がないので、最初の3つの要素はありませんが、十分な一致要素を見つけたらコードが短絡してしまいます。一致する要素。どちらもポイントがありますが、私がOPが求めていることは... – Holger

+0

明らかに、OPは両方向の短絡を望んでいます。 – ZhekaKozlov

0
Set<String> sampleData = downloadFromWeb(); 
int size = (int) (sampleData.size() * coefficient); 
return sampleData.stream().filter(predicate::test).limit(size + 1).count() > size; 
+0

私はこれについて考えましたが、それでも反対の方法では切り詰めません。 – ByeBye

+1

最初の 'size'アイテムのすべてが述語に合格しなかった場合、' size + 1'は良い限度にすぎません。問題の5,000,000という制限は単なる例に過ぎません。 –

+0

@ByeBye良い点ですが、簡潔な解決策のために 'takeWhile'が必要なのではないかと心配しています。 – ZhekaKozlov

4

私はこれが正しいだろうかなりわからない正直に言うと、私は、誰かが一緒に来て、これを確認しますが、ここではカスタムspliteratorを使用しての私の考えであることを願っています:

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

} 

とのために我々は係数5有するだけケアに言っための例では、これは、唯一の4つの要素を生成する:

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

をまたこれは、既知のサイズのspliteratorsことが可能です。

+1

' coefficient'は恐らく0.0と1.0の間です。 –

+1

@JohnKugelmanはい、ここでは実際には 'sampleData.size()* coefficient'です。私はより良い名前を考えることができませんでした.. – Eugene

+0

up !!!私は、唯一の方法は、短絡機能をサポートするカスタムスプライテータを作成することだと思います。 –

関連する問題