Is it possible to merge iterators in Java? I have two iterators and I want to combine/merge them so that I could iterate though their elements in one go (in same loop) rather than two steps. Is that possible?
Note that the number of elements in the two lists can be different therefore one loop over both lists is not the solution.
Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId());
Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());
while(pUsers.hasNext()) {
User user = pUsers.next();
.....
}
while(sUsers.hasNext()) {
User user = sUsers.next();
.....
}
Guava (formerly Google Collections) has Iterators.concat.
Also the Apache Commons Collection have several classes for manipulating Iterators, like the IteratorChain, that wraps a number of Iterators.
You could create your own implementation of the
Iterator
interface which iterates over the iterators:(I've not added generics to the Iterator for brevity.) The implementation is not too hard, but isn't the most trivial, you need to keep track of which
Iterator
you are currently iterating over, and callingnext()
you'll need to iterate as far as you can through the iterators until you find ahasNext()
that returnstrue
, or you may hit the end of the last iterator.I'm not aware of any implementation that already exists for this.Update:
I've up-voted Andrew Duffy's answer - no need to re-invent the wheel. I really need to look into Guava in more depth.
I've added another constructor for a variable number of arguments - almost getting off topic, as how the class is constructed here isn't really of interest, just the concept of how it works.
I haven't written Java code in a while, and this got me curious to whether I've still "got it".
First try:
You could of course use more Collection classes rather than a pure array + index counter, but this actually feels a bit cleaner than the alternative. Or am I just biased from writing mostly C these days?
Anyway, there you go. The answer to you question is "yes, probably".
an iterator comes FROM a collection or a set.
why not use the method already available
Collection.addAll(Collection c);
and then create your iterator from the last object.
this way, your iterator will iterate all the contents of both collection.
move your loop to a method and pass the iterator to method.
You can use my version of an extendable iterator. It uses a double-ended queue of iterators which to me makes sense:
Starting with Java 8 and later this can be done without external dependencies using Stream API. This also allows concatenation of iterator with other types of streams.
I would refactor the original design from:
To something like:
The Merged Iterator:
The
concat
method to create anIterable
:Simple JUnit test:
You can try
ConcatIterator
from Cactoos:Also check
ConcatIterable
, which concatenatesIterable
s.In the Apache Commons Collections there is
public static <E> Iterator<E> org.apache.commons.collections4.IteratorUtils.chainedIterator(Collection<Iterator<? extends E>> iterators)
that sayswhich should be what you want.
every
Iterator
object holds own memory location (adress), so you can't simply "merge" them. except if you extenditerator
class and write your own implementation there.If you are dealing with the same number of objects in both iterators an alternative solution would be to process two iterators in one loop like this :