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

是否可以在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();
  .....
}
Jahanzeb Farooq asked 2020-08-06T20:48:08Z
14个解决方案
49 votes

番石榴(以前称为Google Collections)具有Iterators.concat。

Andrew Duffy answered 2020-08-06T20:48:13Z
18 votes

同样,Apache Commons Collection有几个用于操纵Iterators的类,例如IteratorChain,它包装了许多Iterators。

Ither answered 2020-08-06T20:48:33Z
16 votes

您可以创建自己的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中。)实现不是很困难,但并不是最简单的,您需要跟踪当前正在迭代的Iterator,然后调用next() 通过迭代器进行最大程度的迭代,直到找到一个返回truehasNext(),否则您可能会碰到最后一个迭代器的末尾。

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

更新:
我对安德鲁·达菲(Andrew Duffy)的答案表示反对-无需重新发明轮子。 我真的需要更深入地研究番石榴。

我为可变数量的参数添加了另一个构造函数-几乎没有话题了,因为在这里如何构造类并不是真正令人感兴趣的,只是它如何工作的概念。

Noel M answered 2020-08-06T20:49:16Z
12 votes

我已经有一段时间没有写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语言?

无论如何,你去了。 您的问题的答案是“可能”。

Christoffer answered 2020-08-06T20:49:49Z
3 votes

将循环移至方法并将迭代器传递至method。

void methodX(Iteartor x) {
    while (x.hasNext()) {
        ....
    }
}
mhshams answered 2020-08-06T20:50:09Z
3 votes

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

p01ntbl4nk answered 2020-08-06T20:50:46Z
3 votes
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();
    }
}
clelson answered 2020-08-06T20:51:02Z
2 votes

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

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);
        }
    }
}
Reut Sharabani answered 2020-08-06T20:51:22Z
1 votes

我将从以下位置重构原始设计:

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, ...);
Billworth Vandory answered 2020-08-06T20:51:46Z
1 votes

合并的迭代器:

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++;
    }
}
benez answered 2020-08-06T20:52:14Z
1 votes

您可以从Cactoos尝试Iterable

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

还要检查Iterable,它连接了Iterable

yegor256 answered 2020-08-06T20:52:39Z
1 votes

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

Streams.concat(StreamSupport.stream(<iter1>, false), StreamSupport.stream(<iter2>, false));
Taras Alenin answered 2020-08-06T20:52:59Z
0 votes

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

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

   while (iterator1.hasNext() && iterator2.hasNext()) {
      // code
    }
Youssef answered 2020-08-06T20:53:23Z
0 votes

在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
    }
}
Sled answered 2020-08-06T20:53:52Z
translate from https://stackoverflow.com:/questions/3610261/is-it-possible-to-merge-iterators-in-java