是否可以在Java中合并迭代器?

时间:2010-08-31 14:58:44

标签: java iterator iteration

是否可以在Java中合并迭代器?我有两个迭代器,我想组合/合并它们,以便我可以一次性迭代它们的元素(在同一个循环中)而不是两个步骤。那可能吗?

请注意,两个列表中的元素数量可能不同,因此两个列表中的一个循环不是解决方案。

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

14 个答案:

答案 0 :(得分:49)

Guava(以前称为Google Collections)有Iterators.concat

答案 1 :(得分:18)

Apache Commons Collection还有几个用于操作迭代器的类,如IteratorChain,它包含了许多迭代器。

答案 2 :(得分:16)

您可以创建自己的Iterator接口实现,迭代遍历迭代器:

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 */ }
}

(为了简洁起见,我没有在迭代器中添加泛型。)实现并不是太难,但不是最简单的,你需要跟踪哪个{{1}你正在迭代,调用Iterator你需要尽可能迭代通过迭代器,直到你找到一个返回next()的{​​{1}},或者你可以点击最后一个迭代器的结尾。

我不知道任何已经存在的实现。

更新
我已经投了Andrew Duffy's回答 - 没有必要重新发明轮子。我真的需要更深入地研究番石榴。

我为可变数量的参数添加了另一个构造函数 - 几乎脱离主题,因为这里构造类的方式并不是真正令人感兴趣的,只是它的工作原理。

答案 3 :(得分:12)

我有一段时间没有编写Java代码,这让我很好奇我是否仍然“得到它”。

首先尝试:

import java.util.Iterator;
import java.util.Arrays; /* For sample code */

public class IteratorIterator<T> implements Iterator<T> {
    private final Iterator<T> is[];
    private int current;

    public IteratorIterator(Iterator<T>... iterators)
    {
            is = iterators;
            current = 0;
    }

    public boolean hasNext() {
            while ( current < is.length && !is[current].hasNext() )
                    current++;

            return current < is.length;
    }

    public T next() {
            while ( current < is.length && !is[current].hasNext() )
                    current++;

            return is[current].next();
    }

    public void remove() { /* not implemented */ }

    /* Sample use */
    public static void main(String... args)
    {
            Iterator<Integer> a = Arrays.asList(1,2,3,4).iterator();
            Iterator<Integer> b = Arrays.asList(10,11,12).iterator();
            Iterator<Integer> c = Arrays.asList(99, 98, 97).iterator();

            Iterator<Integer> ii = new IteratorIterator<Integer>(a,b,c);

            while ( ii.hasNext() )
                    System.out.println(ii.next());
    }
}

当然可以使用更多的Collection类而不是纯数组+索引计数器,但这实际上感觉比替代方案更清晰。或者我现在偏向于写作大部分是C?

无论如何,你去吧。你回答的问题是“是的,可能”。

答案 4 :(得分:3)

将循环移动到方法并将迭代器传递给方法。

void methodX(Iteartor x) {
    while (x.hasNext()) {
        ....
    }
}

答案 5 :(得分:3)

迭代器来自集合或集合 为什么不使用已有的方法
Collection.addAll(Collection c);
然后从最后一个对象创建迭代器 这样,你的迭代器将遍历两个集合的所有内容。

答案 6 :(得分:3)

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

答案 7 :(得分:2)

您可以使用可扩展迭代器的my version。它使用了一个双端的迭代器队列,这对我来说很有意义:

import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedDeque;

public class ExtendableIterator<T> implements Iterator<T> {

    public Deque<Iterator<T>> its = new ConcurrentLinkedDeque<Iterator<T>>();

    public ExtendableIterator() {

    }

    public ExtendableIterator(Iterator<T> it) {
        this();
        this.extend(it);
    }

    @Override
    public boolean hasNext() {
        // this is true since we never hold empty iterators
        return !its.isEmpty() && its.peekLast().hasNext();
    }

    @Override
    public T next() {
        T next = its.peekFirst().next();
        if (!its.peekFirst().hasNext()) {
            its.removeFirst();
        }
        return next;
    }

    public void extend(Iterator<T> it) {
        if (it.hasNext()) {
            its.addLast(it);
        }
    }
}

答案 8 :(得分:2)

从Java 8开始,可以使用Stream API在没有外部依赖的情况下完成此操作。这也允许将迭代器与其他类型的流串联。

Streams.concat(StreamSupport.stream(<iter1>, false), StreamSupport.stream(<iter2>, false));

答案 9 :(得分:1)

我会重构原始设计:

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

类似于:

Iterator<User> users = userService.getUsersInGroup(group.getId(), User.PRIMARY, User.SECONDARY, ...);

答案 10 :(得分:1)

Merged Iterator:

public function groups($eventId)
{
    return Group::where('event_id', $eventId)->with('individuals')->paginate(5);
}

创建import static java.util.Arrays.asList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; public class ConcatIterator<T> implements Iterator<T> { private final List<Iterable<T>> iterables; private Iterator<T> current; @SafeVarargs public ConcatIterator(final Iterable<T>... iterables) { this.iterables = new LinkedList<>(asList(iterables)); } @Override public boolean hasNext() { checkNext(); return current != null && current.hasNext(); } @Override public T next() { checkNext(); if (current == null || !current.hasNext()) throw new NoSuchElementException(); return current.next(); } @Override public void remove() { if (current == null) throw new IllegalStateException(); current.remove(); } private void checkNext() { while ((current == null || !current.hasNext()) && !iterables.isEmpty()) { current = iterables.remove(0).iterator(); } } } 的{​​{1}}方法:

concat

简单的JUnit测试:

Iterable

答案 11 :(得分:1)

您可以尝试ConcatIterator中的Cactoos

Iterator<String> names = new ConcatIterator<>(
  Arrays.asList("Sarah", "Mary").iterator(),
  Arrays.asList("Jeff", "Johnny").iterator(),
);

同时检查ConcatIterable,它连接Iterable s。

答案 12 :(得分:0)

每个Iterator对象都拥有自己的内存位置(地址),因此您无法简单地“合并”它们。除非你扩展iterator类并在那里编写自己的实现。

如果你在两个迭代器中处理相同数量的对象,另一种解决方案是在一个循环中处理两个迭代器,如下所示:

   while (iterator1.hasNext() && iterator2.hasNext()) {
      // code
    }

答案 13 :(得分:0)

Apache Commons Collections中,有public static <E> Iterator<E> org.apache.commons.collections4.IteratorUtils.chainedIterator(Collection<Iterator<? extends E>> iterators)

  

获取一个迭代器,该迭代器一个接一个地迭代一系列迭代器。

这应该是您想要的。

import java.util.Arrays;
import java.util.Iterator;

import org.apache.commons.collections4.IteratorUtils;
//also works: import org.apache.commons.collections.IteratorUtils;

class Scratch {
    public static void main( String[] args ) {
        final Iterator<String> combinedIterator = IteratorUtils.chainedIterator(
                Arrays.asList( "a", "b", "c" ).iterator(),
                Arrays.asList( "1", "2", "3" ).iterator()
            );
        while( combinedIterator.hasNext() ){
            System.out.println( combinedIterator.next() );
        }
        // "abc123" will have been printed out
    }
}