如何在 Java 中制作迭代器的副本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5963399/
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
How can I make a copy of an iterator in Java?
提问by Luis
We have a list of elements and have a very simplistic collision detection where we check every object against every other object.
我们有一个元素列表,并且有一个非常简单的碰撞检测,我们检查每个对象与每个其他对象。
The check is commutative, so to avoid repeating it twice, we would do this in C++:
检查是可交换的,因此为了避免重复两次,我们将在 C++ 中执行此操作:
for (list<Object>::iterator it0 = list.begin(); it0 != list.end(); ++it0)
{
for (list<Object>::iterator it1 = it0; it1 != list.end(); ++it1)
{
Test(*it0, *it1);
}
}
The key bit here is the copy
这里的关键是副本
it1 = it0
How would you write this in Java?
你会如何用 Java 写这个?
采纳答案by Michael Borgwardt
You cannot copy Java iterators, so you'll have to do it without them:
您无法复制 Java 迭代器,因此您必须在没有它们的情况下进行复制:
for(int i=0; i<list.size(); i++){
for(int j=i; j<list.size(); j++){
Test(list.get(i), list.get(j));
}
}
回答by Pa?lo Ebermann
You can do this with ListIterator:
你可以用 ListIterator 做到这一点:
for(ListIterator<O> outer = list.listIterator(); outer.hasNext() ; ) {
O oVal = outer.next();
for(ListIterator<O> inner = list.listIterator(outer.nextIndex()); inner.hasNext(); ) {
Test(oVal, inner.next());
}
}
For a linked list (which has slow index access) the list.listIterator(index)
still needs to iterate to the right place, though.
But this way it is only O(n2) (and you can't get better than this) instead of O(n3) like the index-access in the other answers then. (You might be even faster if you copy your list first to an array, but it is only a constant factor here.)
但是,对于链表(索引访问速度较慢),list.listIterator(index)
仍然需要迭代到正确的位置。但是这样它只是 O(n2) (并且你不能得到比这更好的)而不是 O(n3) 就像其他答案中的索引访问那样。(如果您先将列表复制到数组中,速度可能会更快,但这只是一个常数因素。)
Of course, if you usually need index-based access (or this iterator-cloning), you would better use an array-based list (or a custom list whose iterator supports cloning).
当然,如果您通常需要基于索引的访问(或此迭代器克隆),则最好使用基于数组的列表(或迭代器支持克隆的自定义列表)。
回答by Luca Citi
For a linked list (which has slow index access), I think there is a way to do it without incurring in the O(n2) slowdown that Pa?lo mentioned. 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. See iterRevIterator
in the code below. 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.
The difference is not enormous...
对于链表(索引访问速度较慢),我认为有一种方法可以在不引起 Pa?lo 提到的 O(n2) 减速的情况下进行。只要不关心列表的访问顺序,就可以从最后一个元素开始外循环并往回迭代,从第一个元素开始内循环并向前迭代,直到两个迭代器相遇。请参阅iterRevIterator
下面的代码。对 的调用list.listIterator(list.size())
很快,因为list
是 a LinkedList
,即双向链表,并且访问最后一个元素不需要遍历列表。差别不是很大...
iterIndex: 384.59ms sum=29656666
iterIterator: 1.91ms sum=29656666
iterRevIterator: 1.55ms sum=29656666
but still significant.
但仍然很重要。
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
public class TestIter {
public static int iterIndex(List<Integer> list) {
int sum = 0;
for(int i = 0; i < list.size(); ++i) {
for(int j = i+1; j < list.size(); ++j) {
sum += list.get(i) * list.get(j);
}
}
return sum;
}
public static int iterIterator(List<Integer> list) {
int sum = 0;
for(ListIterator<Integer> outer = list.listIterator(); outer.hasNext() ; ) {
Integer oVal = outer.next();
for(ListIterator<Integer> inner = list.listIterator(outer.nextIndex()); inner.hasNext(); ) {
sum += oVal * inner.next();
}
}
return sum;
}
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;
}
public static void main(String[] args) {
int size = 1000;
int rep = 100;
int sum = 0;
// List<Integer> list = new ArrayList<Integer>();
List<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < size; ++i) {
list.add(i);
}
long startTime = System.currentTimeMillis();
for (int i = 0; i < rep; ++i) {
sum = iterIndex(list);
}
System.out.println("iterIndex: " + (float)(System.currentTimeMillis() - startTime)/rep + "ms sum=" + sum);
startTime = System.currentTimeMillis();
for (int i = 0; i < rep; ++i) {
sum = iterIterator(list);
}
System.out.println("iterIterator: " + (float)(System.currentTimeMillis() - startTime)/rep + "ms sum=" + sum);
startTime = System.currentTimeMillis();
for (int i = 0; i < rep; ++i) {
sum = iterRevIterator(list);
}
System.out.println("iterRevIterator: " + (float)(System.currentTimeMillis() - startTime)/rep + "ms sum=" + sum);
}
}
回答by Steve Lancashire
for(int i = 0; i < list.size(); i++) {
for(int j = i; j < list.size(); j++){
Test(list.get(i), list.get(j));
}
}