For example, I need something like:
Collection<String> collection = /* ... */;
Stream<Object> stream = /* ... */;
boolean containsAll = stream.map(Object::toString).containsAll(collection);
Of course, I could accumulate all elements of the stream into another Collection
using collect()
method and the call Collection.containsAll()
, but what if the stream is too big and it is inefficient to process all its elements?
allMatch() method. The allMatch() method returns true if all elements of the stream matches with the given predicate. It can be used as follows to check if all elements in a list are the same.
Stream count() method in Java with examples long count() returns the count of elements in the stream. This is a special case of a reduction (A reduction operation takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation).
Getting Started with Streams Sequence of elements: A stream provides an interface to a sequenced set of values of a specific element type. However, streams don't actually store elements; they are computed on demand. Source: Streams consume from a data-providing source such as collections, arrays, or I/O resources.
No storage. Streams don't have storage for values; they carry values from a source (which could be a data structure, a generating function, an I/O channel, etc) through a pipeline of computational steps.
This should do the trick:
Set<String> set = new HashSet<>(collection);
boolean containsAll = set.isEmpty() || stream.map(Object::toString)
.anyMatch(s -> set.remove(s) && set.isEmpty());
The solution might look confusing, but the idea is straightforward:
collection
we wrap it into a HashSet
. (In case your stream
is a parallel one, then you will have to use a concurrent hash set. See this post for more details)collection
(or set
) is empty then we return true
without processing the stream
stream
we try to remove it from set
. In case the result of Set::remove
is true
(hence it was contained by set
) and the set
is empty after removal, we can conclude that stream
contained all the elements of initial collection
.Stream::anyMatch
is a short-circuiting one. So it will stop iterating over stream
once the set
is empty. In worst case we will process the entire stream. Perhaps this is a bit more readable form:
Set<String> set = new HashSet<>(collection);
boolean containsAll = set.isEmpty() || stream.map(Object::toString)
.filter(set::remove)
.anyMatch(__ -> set.isEmpty());
If the collection
can contain duplicates and there is a requirement to check if stream
contains all of them, then we will need to maintain a concurrent map of counters.
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());
The code slightly changed but the idea is the same.
Create a Set from Collection<String>
to make search operation faster O(1)
Set<String> set = new HashSet<>(collection);
Then use allMatch
to check every item in stream contains in set or not
boolean containsAll = stream.map(Object::toString)
.allMatch(s -> set.contains(s));
Another way is filter by not contained in set and use limit(1)
for optimization
boolean isContains = stream.map(Object::toString)
.filter(s -> !set.contains(s))
.limit(1)
.count() > 0;
Regardless of how big the Stream
is, you will have to process all of its elements if it does not contain all the elements of the Collection
.
You could save processing time if a small prefix of the Stream
contains all the elements of Collection
, and the Collection
is much smaller than the Stream
.
boolean containsAll =
stream.map(Object::toString)
.filter(s -> collection.contains(s)) // it would be wise to convert collection to a Set
.limit(collection.size())
.count() == collection.size();
Note that if the Stream
may contain multiple copies of the same element of the Collection
, you may have to add a .distinct()
operation after the filter()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With