在 Java 中克隆迭代器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7758202/
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-10-30 21:17:51  来源:igfitidea点击:

Clone an Iterator in Java?

javaiterator

提问by Thomas Padron-McCarthy

In a game I have a list of players, let's say like this:

在游戏中,我有一个玩家列表,让我们这样说:

LinkedList<String> players = new LinkedList<String>();

I want to let each player interact with each of the other players, so I write two nested loops:

我想让每个玩家与其他玩家互动,所以我写了两个嵌套循环:

Iterator<String> i1 = players.iterator();
while (i1.hasNext()) {
    String p1 = i1.next();
    Iterator<String> i2 = players.iterator();
    // But I want to do this: Iterator<String> i2 = i1.clone();
    while (i2.hasNext()) {
        String p2 = i2.next();
        System.out.println("Interact: " + p1 + ", " + p2);
    }
}

Since I only want each pair of players to interact once, I want to start the inner loop with the player after the outer loop's current player. So I want to clone the iterator, but that doesn't compile.

因为我只希望每对玩家交互一次,所以我想在外循环的当前玩家之后开始与玩家的内循环。所以我想克隆迭代器,但这不能编译。

So, what should I do instead?

那么,我应该怎么做呢?

回答by NPE

The following will do it:

以下将做到这一点:

ListIterator<String> i1 = players.listIterator(0);
while (i1.hasNext()) {
    String p1 = i1.next();
    ListIterator<String> i2 = players.listIterator(i1.nextIndex());
    while (i2.hasNext()) {
        String p2 = i2.next();
        System.out.println("Interact: " + p1 + ", " + p2);
    }
}

It relies on the ListIterator's ability to start from the given position and to also know its current position.

它依赖于ListIterator从给定位置开始并知道其当前位置的能力。

回答by aioobe

In addition to aix answer, I'd like to point out that however you create an iterator starting at a specific index, it's bound to be a linear operation. If it wasn't, you would be able to do arbitrary access to the list in constant time using

除了aix answer 之外,我想指出的是,无论您创建一个从特定索引开始的迭代器,它都必然是一个线性操作。如果不是,您将能够使用恒定时间对列表进行任意访问

elementN = createIterator(linkedList, N).next();

which would be contradictory.

这将是矛盾的。

In your situation I therefore believe that the most efficient solution would actually be to do

因此,在您的情况下,我认为最有效的解决方案实际上是做

List<String> tmp = new ArrayList<String>(players);
for (int p1 = 0; p1 < tmp.size(); p1++)
    for (int p2 = p1+1; p2 < tmp.size(); p2++)
        System.out.println("Interact: " + tmp.get(p1) + ", " + tmp.get(p2));

Note however, that it is stillthe same complexity as the solution by aix; O(n2)but probably with a smaller constant factor.

但是请注意,它仍然与 aix 的解决方案具有相同的复杂性;O(n 2)但可能具有较小的常数因子。

回答by Luca Citi

For a solution that avoids the linear cost associated to listIterator(int)(NPE's answer), see my answer to a similar question. In brief, as long as you don't care about the order the list is visited, you can start the outer loop from the last element and iterate back, and start the inner loop from the first element and iterate forward until the two iterators meet. The call to list.listIterator(list.size()) is fast because list is a LinkedList, i.e. a doubly-linked list, and accessing the last element does not require iterating through the list. See example below:

有关避免与listIterator(int)(NPE 的回答)相关的线性成本的解决方案,请参阅我对类似问题的回答。简而言之,只要不关心列表的访问顺序,就可以从最后一个元素开始外循环并往回迭代,从第一个元素开始内循环并向前迭代,直到两个迭代器相遇. 对 list.listIterator(list.size()) 的调用很快,因为 list 是一个 LinkedList,即双向链表,并且访问最后一个元素不需要遍历列表。请参阅下面的示例:

public static int iterRevIterator(List<Integer> list) {
    int sum = 0;
    for(ListIterator<Integer> outer = list.listIterator(list.size()); outer.hasPrevious(); ) {
        Integer oVal = outer.previous();
        for(ListIterator<Integer> inner = list.listIterator(); inner.nextIndex() <= outer.previousIndex(); ) {
            sum += oVal * inner.next();
        }
    }
    return sum;
}