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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3610261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 02:37:36  来源:igfitidea点击:

Is it possible to merge iterators in Java?

javaiteratoriteration

提问by Jahanzeb Farooq

Is it possible to merge iterators in Java? I have two iterators and I want to combine/merge them so that I could iterate though their elements in one go (in same loop) rather than two steps. Is that possible?

是否可以在 Java 中合并迭代器?我有两个迭代器,我想合并/合并它们,以便我可以一次性(在同一循环中)而不是两步迭代它们的元素。那可能吗?

Note that the number of elements in the two lists can be different therefore one loop over both lists is not the solution.

请注意,两个列表中的元素数量可能不同,因此对两个列表进行一次循环不是解决方案。

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

回答by Noel M

You could create your own implementation of the Iteratorinterface which iterates over the iterators:

您可以创建自己的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 */ }
}

(I've not added generics to the Iterator for brevity.)The implementation is not too hard, but isn't the most trivial, you need to keep track of which Iteratoryou are currently iterating over, and calling next()you'll need to iterate as far as you can through the iterators until you find a hasNext()that returns true, or you may hit the end of the last iterator.

(为简洁起见,我没有在 Iterator 中添加泛型。)实现并不太难,但不是最简单的,您需要跟踪Iterator您当前正在迭代的内容,并且调用next()您需要迭代尽可能通过迭代器,直到找到hasNext()返回的true,或者您可能会到达最后一个迭代器的末尾。

I'm not aware of any implementation that already exists for this.

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

Update:
I've up-voted Andrew Duffy'sanswer - no need to re-invent the wheel. I really need to look into Guava in more depth.

更新:
我对Andrew Duffy 的回答投了赞成票- 无需重新发明轮子。我真的需要更深入地研究番石榴。

I've added another constructor for a variable number of arguments - almost getting off topic, as how the class is constructed here isn't really of interest, just the concept of how it works.

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

回答by Andrew Duffy

Guava(formerly Google Collections) has Iterators.concat.

Guava(以前的 Google Collections)有Iterators.concat

回答by mhshams

move your loop to a method and pass the iterator to method.

将循环移动到一个方法并将迭代器传递给方法。

void methodX(Iterator x) {
    while (x.hasNext()) {
        ....
    }
}

回答by Youssef

every Iteratorobject holds own memory location (adress), so you can't simply "merge" them. except if you extend iteratorclass and write your own implementation there.

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

If you are dealing with the same number of objectsin both iterators an alternative solution would be to process two iterators in one loop like this :

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

   while (iterator1.hasNext() && iterator2.hasNext()) {
      // code
    }

回答by Christoffer

I haven't written Java code in a while, and this got me curious to whether I've still "got it".

我已经有一段时间没有编写 Java 代码了,这让我很好奇我是否仍然“明白”了。

First try:

第一次尝试:

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

You couldof course use more Collection classes rather than a pure array + index counter, but this actually feels a bit cleaner than the alternative. Or am I just biased from writing mostly C these days?

可能当然使用更集合类,而不是一个纯粹的阵列+索引计数器,但其实这感觉有点清洁比其他。或者我现在只是偏向于主要编写 C 语言?

Anyway, there you go. The answer to you question is "yes, probably".

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

回答by p01ntbl4nk

an iterator comes FROM a collection or a set.
why not use the method already available
Collection.addAll(Collection c);
and then create your iterator from the last object.
this way, your iterator will iterate all the contents of both collection.

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

回答by Ither

Also the Apache Commons Collectionhave several classes for manipulating Iterators, like the IteratorChain, that wraps a number of Iterators.

此外,Apache Commons Collection有几个用于操作迭代器的类,例如IteratorChain,它包装了许多迭代器。

回答by Billworth Vandory

I would refactor the original design from:

我将从以下方面重构原始设计:

Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId());
Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());

To something like:

类似于:

Iterator<User> users = userService.getUsersInGroup(group.getId(), User.PRIMARY, User.SECONDARY, ...);

回答by Reut Sharabani

You can use my versionof an extendable iterator. It uses a double-ended queue of iterators which to me makes sense:

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

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

回答by benez

The Merged Iterator:

合并迭代器:

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

}

The concatmethod to create an Iterable:

concat创建一个的方法Iterable

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

Simple JUnit test:

简单的 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++;
    }
}