Is it possible to merge iterators in Java?

2019-01-07 18:58发布

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

12条回答
来,给爷笑一个
2楼-- · 2019-01-07 19:33
public class IteratorJoin<T> implements Iterator<T> {
    private final Iterator<T> first, next;

    public IteratorJoin(Iterator<T> first, Iterator<T> next) {
        this.first = first;
        this.next = next;
    }

    @Override
    public boolean hasNext() {
        return first.hasNext() || next.hasNext();
    }

    @Override
    public T next() {
        if (first.hasNext())
            return first.next();
        return next.next();
    }
}
查看更多
相关推荐>>
3楼-- · 2019-01-07 19:35

You could create your own implementation of the Iterator interface which iterates over the iterators:

public class IteratorOfIterators implements Iterator {
    private final List<Iterator> iterators;

    public IteratorOfIterators(List<Iterator> iterators) {
        this.iterators = iterators;
    }

    public IteratorOfIterators(Iterator... iterators) {
        this.iterators = Arrays.asList(iterators);
    }


    public boolean hasNext() { /* implementation */ }

    public Object next() { /* implementation */ }

    public void remove() { /* implementation */ }
}

(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 calling next() you'll need to iterate as far as you can through the iterators until you find a hasNext() that returns true, 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.

查看更多
虎瘦雄心在
4楼-- · 2019-01-07 19:35

move your loop to a method and pass the iterator to method.

void methodX(Iteartor x) {
    while (x.hasNext()) {
        ....
    }
}
查看更多
Fickle 薄情
5楼-- · 2019-01-07 19:41

every Iterator object holds own memory location (adress), so you can't simply "merge" them. except if you extend iterator 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 :

   while (iterator1.hasNext() && iterator2.hasNext()) {
      // code
    }
查看更多
叼着烟拽天下
6楼-- · 2019-01-07 19:45

Also the Apache Commons Collection have several classes for manipulating Iterators, like the IteratorChain, that wraps a number of Iterators.

查看更多
Emotional °昔
7楼-- · 2019-01-07 19:47

I would refactor the original design from:

Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId());
Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());

To something like:

Iterator<User> users = userService.getUsersInGroup(group.getId(), User.PRIMARY, User.SECONDARY, ...);
查看更多
登录 后发表回答