ストリームは、すべてのコレクションの要素が含まれているかどうかを確認する方法はありますか?

Nolequen:

例えば、私のようなものが必要になります。

Collection<String> collection = /* ... */;
Stream<Object> stream = /* ... */;
boolean containsAll = stream.map(Object::toString).containsAll(collection);

もちろん、私は別のものに、ストリームのすべての要素を蓄積することができCollection使用collect()方法や呼び出しCollection.containsAll()が、ストリームが大きすぎる場合にはどのような、そのすべての要素を処理するのは非効率的ですか?

ETO:

これは、トリックを行う必要があります。

Set<String> set = new HashSet<>(collection);
boolean containsAll = set.isEmpty() || stream.map(Object::toString)
                                             .anyMatch(s -> set.remove(s) && set.isEmpty());

解決策は混乱に見えるかもしれませんが、考え方は簡単です。

  1. 上の複数の反復を防止するためにcollection、我々はにそれを包みますHashSet(あなたの場合はstream、並列一つであり、あなたは同時ハッシュセットを使用する必要があります。参照この記事の詳細については)
  2. 場合collection(またはset)空である我々は返すtrue処理せずstream
  3. 各エントリのためにstream、私たちからそれを削除してみてくださいset場合の結果がSet::removeあるtrue(したがってそれはに含まれたset)とsetを除去した後に空である、我々は結論付けることができstream、初期のすべての要素を含んでいましたcollection
  4. 端末操作はStream::anyMatch短絡です。それは反復の上に停止しますので、stream一度set空になっています。最悪のケースでは、全体のストリームを処理します。

おそらくこれは、もう少し読みやすい形式です。

Set<String> set = new HashSet<>(collection);
boolean containsAll = set.isEmpty() || stream.map(Object::toString)
                                             .filter(set::remove)
                                             .anyMatch(__ -> set.isEmpty());

場合はcollection、重複を含めることができますし、かどうかを確認する必要がありstream、それらのすべてが含まれていますが、我々は、カウンタの同時マップを維持する必要があります。

Map<String, AtomicLong> map = new ConcurrentHashMap<>();
collection.forEach(s -> map.computeIfAbsent(s, __ -> new AtomicLong()).incrementAndGet());
boolean containsAll = map.isEmpty() || stream.map(Object::toString)
                                             .filter(map::containsKey)
                                             .filter(s -> map.get(s).decrementAndGet() == 0)
                                             .filter(s -> map.remove(s) != null)
                                             .anyMatch(__ -> map.isEmpty());

コード若干変更が、考え方は同じです。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=311884&siteId=1