Объединение нескольких итераторов в java
Кто-нибудь знает, как присоединиться к нескольким итераторам в Java? Решение, которое я нашел, сначала перебирает один итератор, а затем переходит к следующему. Однако, что я хочу, когда next() вызывается, он сначала возвращает первый элемент из первого итератора. В следующий раз, когда next() вызывается, он возвращает первый элемент из второго итератора и т.д.
Спасибо
Ответы
Ответ 1
Использование Guava 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();
}
};
Это даст вам желаемый "чередующийся" порядок, достаточно умный, чтобы иметь дело с коллекциями разных размеров, и это довольно компактно. (Вы можете использовать ArrayDeque
вместо LinkedList
для скорости, предполагая, что вы находитесь на Java 6 +.)
Если вы действительно не можете мириться с другой сторонней библиотекой, вы можете более или менее сделать то же самое с некоторой дополнительной работой, например:
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(); }
};
Для справки, поведение "all of iter1, all of iter2 и т.д." также можно получить, используя Iterators.concat(Iterator<Iterator>)
и его перегрузки.
Ответ 2
Похоже, вы хотите чередование. Что-то вроде этого - полностью непроверено...
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();
}
}
}
Ответ 3
Изменить:
Ой, неверно истолковал свой вопрос.
Вам действительно нужен итератор чередования, а не сложный итератор:
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");
}
}
Ответ 4
Самый простой подход -
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);