在java中连接多个迭代器

时间:2012-02-08 19:29:04

标签: java iterator

有人知道如何在Java中加入多个迭代器吗?我发现的解决方案首先迭代一个迭代器,然后继续下一个迭代器。但是,我想要的是当next()被调用时,它首先返回第一个迭代器中的第一个元素。下次调用next()时,它将返回第二个迭代器中的第一个元素,依此类推。

由于

4 个答案:

答案 0 :(得分:10)

为简单起见,请使用Guava's AbstractIterator

final List<Iterator<E>> theIterators;
return new AbstractIterator<E>() {
  private Queue<Iterator<E>> queue = new LinkedList<Iterator<E>>(theIterators);
  @Override protected E computeNext() {
    while(!queue.isEmpty()) {
      Iterator<E> topIter = queue.poll();
      if(topIter.hasNext()) {
        E result = topIter.next();
        queue.offer(topIter);
        return result;
      }
    }
    return endOfData();
  }
};

这将为您提供所需的“交错”顺序,它足够智能地处理具有不同大小的集合,并且它非常紧凑。 (假设您使用的是Java 6 +,您可能希望使用ArrayDeque代替LinkedList来提高速度。)

如果你真的,真的不能容忍另一个第三方库,你可以或多或少地通过一些额外的工作做同样的事情,如下:

return new Iterator<E>() {
  private Queue<Iterator<E>> queue = new LinkedList<Iterator<E>>(theIterators);
  public boolean hasNext() {
    // If this returns true, the head of the queue will have a next element
    while(!queue.isEmpty()) {
      if(queue.peek().hasNext()) {
        return true;
      }
      queue.poll();
    }
    return false;
  }
  public E next() {
    if(!hasNext()) throw new NoSuchElementException();
    Iterator<E> iter = queue.poll();
    E result = iter.next();
    queue.offer(iter);
    return result;
  }
  public void remove() { throw new UnsupportedOperationException(); }
};

作为参考,也可以使用Iterators.concat(Iterator<Iterator>)及其重载来获取“所有iter1,所有iter2等”行为。

答案 1 :(得分:3)

听起来你想要交错。这样的事情 - 完全未经测试......

public class InterleavingIterable<E> implements Iterable<E> {

    private final Iterable<? extends E> first;
    private final Iterable<? extends E> second;

    public InterleavingIterable(Iterable<? extends E> first,
                                Iterable<? extends E> second) {
        this.first = first;
        this.second = second;
    }

    public Iterator<E> iterator() {
        return new InterleavingIterator<E>(first.iterator(),
                                           second.iterator());
    }

    private static class InterleavingIterator<E> implements Iterator<E> {

        private Iterator<? extends E> next;
        private Iterator<? extends E> current;

        private InterleavingIterator(Iterator<? extends E> first,
                                     Iterator<? extends E> second) {
            next = first;
            current = second;
        }

        public boolean hasNext() {
            return next.hasNext() || (current != null && current.hasNext());
        }

        public E next() throws NoSuchElementException {
            if (next.hasNext()) {
                E ret = next.next();
                if (current != null) {
                    Iterator<? extends E> tmp = current;
                    current = next;
                    next = tmp;
                }
                return ret;
            } else {
                // Nothing left in next... check "current"
                if (current == null || !current.hasNext()) {
                    throw new NoSuchElementException();
                }
                next = current;
                current = null;
                return current.next();
            }
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}

答案 2 :(得分:0)

编辑: 哎呀,误解了你的问题。 实际上你需要一个交错迭代器,而不是复合迭代器:

class InterleavingIterator<T> implements Iterator<T> {

    private final Iterator<T> internalIter;

    public InterleavingIterator(final Iterator<T>... iterators) {
        final LinkedList<Iterator<T>> iteratorQueue = new LinkedList<Iterator<T>>();
        for (final Iterator<T> loopIter : iterators) {
            if (loopIter.hasNext()) {
                iteratorQueue.push(loopIter);
            }
        }

        // create the interleaving
        final LinkedList<T> internalList = new LinkedList<T>();
        while (!iteratorQueue.isEmpty()) {
            final Iterator<T> loopIter = iteratorQueue.pop();
            internalList.add(loopIter.next());
            if (loopIter.hasNext()) {
                iteratorQueue.push(loopIter);
            }
        }
        internalIter = internalList.iterator();
    }

    public boolean hasNext() {
        return internalIter.hasNext();
    }

    public T next() {
        return internalIter.next();
    }

    public void remove() {
        throw new UnsupportedOperationException("remove() unsupported");
    }
}

结束编辑。

您需要使用复合迭代器,例如:

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;

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

    private final LinkedList<Iterator<T>> iteratorQueue;
    private Iterator<T> current;

    public CompoundIterator(final Iterator<T>... iterators) {
        this.iteratorQueue = new LinkedList<Iterator<T>>();
        for (final Iterator<T> iterator : iterators) {
            iteratorQueue.push(iterator);
        }
        current = Collections.<T>emptyList().iterator();
    }

    public boolean hasNext() {
        final boolean curHasNext = current.hasNext();
        if (!curHasNext && !iteratorQueue.isEmpty()) {
            current = iteratorQueue.pop();
            return current.hasNext();
        } else {
            return curHasNext;
        }
    }

    public T next() {
        if (current.hasNext()) {
            return current.next();
        }
        if (!iteratorQueue.isEmpty()) {
            current = iteratorQueue.pop();
        }
        return current.next();
    }

    public void remove() {
        throw new UnsupportedOperationException("remove() unsupported");
    }
}

答案 3 :(得分:-1)

最简单的方法是

for(Type1 t1: collection1)
    for(Type2 t2: collection2)

如果您希望它在集合之间执行连接,这将有效。

如果你想迭代两个集合,我只会使用两个循环或用两者创建一个集合。

for(Type t1: collection1)
   process(t1);

for(Type t2: collection2)
   process(t2);

如果你想交错迭代器,你可以使用数组。

Iterator[] iters = { iter1, iter2, ... };
boolean finished;
do {
  finished = true;
  for(Iterator it: iters) {
    if (it.hasNext()) {
       Object obj = it.next();
       // process
       finished = false;
    }
  }
} while(!finished);