Подтвердить что ты не робот

Объединение нескольких итераторов в java

Кто-нибудь знает, как присоединиться к нескольким итераторам в Java? Решение, которое я нашел, сначала перебирает один итератор, а затем переходит к следующему. Однако, что я хочу, когда next() вызывается, он сначала возвращает первый элемент из первого итератора. В следующий раз, когда next() вызывается, он возвращает первый элемент из второго итератора и т.д.

Спасибо

4b9b3361

Ответ 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);