Возможно ли объединить итераторы в Java? - PullRequest
42 голосов
/ 31 августа 2010

Возможно ли объединить итераторы в 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();
  .....
}

Ответы [ 13 ]

49 голосов
/ 31 августа 2010

Гуава (ранее Google Collections) имеет Iterators.concat .

18 голосов
/ 01 сентября 2010

Также Apache Commons Collection имеет несколько классов для манипулирования итераторами, например IteratorChain , который включает в себя несколько итераторов.

16 голосов
/ 31 августа 2010

Вы можете создать собственную реализацию интерфейса 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 */ }
}

(для краткости я не добавил обобщений в итератор.) Реализация не слишком сложная, но не самая тривиальная, вам нужно отслеживать, на каком Iterator вы сейчас выполняете итерацию, и, вызывая next(), вам нужно будет выполнять итерацию настолько, насколько это возможно, с помощью итераторов.пока вы не найдете hasNext(), который возвращает true, или вы можете дойти до конца последнего итератора.

Я не знаю ни одной реализации, которая уже существует для этого.

Обновление: Я проголосовал за ответ Эндрю Даффи - нет необходимости заново изобретать колесо.Мне действительно нужно более детально изучить Guava.

Я добавил еще один конструктор для переменного числа аргументов - почти не в тему, поскольку то, как здесь создается класс, не представляет большого интереса, простопонятие о том, как это работает.

12 голосов
/ 31 августа 2010

Я давно не писал 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 сегодня?

В любом случае, поехали.Ответ на ваш вопрос «да, наверное».

3 голосов
/ 02 марта 2018
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 голосов
/ 01 сентября 2010

Итератор приходит из коллекции или набора.
почему бы не использовать уже доступный метод
Collection.addAll(Collection c);
а затем создайте свой итератор из последнего объекта.
таким образом, ваш итератор будет повторять все содержимое обеих коллекций.

3 голосов
/ 31 августа 2010

переместите ваш цикл в метод и передайте итератор методу.

void methodX(Iteartor x) {
    while (x.hasNext()) {
        ....
    }
}
2 голосов
/ 25 ноября 2015

Вы можете использовать мою версию расширяемого итератора.Он использует двустороннюю очередь итераторов, что для меня имеет смысл:

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);
        }
    }
}
1 голос
/ 19 июня 2017

Вы можете попробовать ConcatIterator из Cactoos :

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

Также проверьте ConcatIterable, который объединяет Iterables.

1 голос
/ 05 января 2017

Объединенный итератор:

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

}

Метод concat для создания Iterable:

@SafeVarargs
public static <T> Iterable<T> concat(final Iterable<T>... iterables) {
    return () -> new ConcatIterator<>(iterables);
}

Простой тест JUnit:

@Test
public void testConcat() throws Exception {
    final Iterable<Integer> it1 = asList(1, 2, 3);
    final Iterable<Integer> it2 = asList(4, 5);
    int j = 1;
    for (final int i : concat(it1, it2)) {
        assertEquals(j, i);
        j++;
    }
}
...