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());
解決策は混乱に見えるかもしれませんが、考え方は簡単です。
- 上の複数の反復を防止するために
collection
、我々はにそれを包みますHashSet
。(あなたの場合はstream
、並列一つであり、あなたは同時ハッシュセットを使用する必要があります。参照この記事の詳細については) - 場合
collection
(またはset
)空である我々は返すtrue
処理せずstream
- 各エントリのために
stream
、私たちからそれを削除してみてくださいset
。場合の結果がSet::remove
あるtrue
(したがってそれはに含まれたset
)とset
を除去した後に空である、我々は結論付けることができstream
、初期のすべての要素を含んでいましたcollection
。 - 端末操作は
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());
コード若干変更が、考え方は同じです。