是否可以在同一列表的另一个迭代中迭代列表?

时间:2011-04-23 04:19:52

标签: java iterator

我在ArrayList中有一些对象,我想执行碰撞检测等。可以这样做:

List<Person> A;
iterA0 = A.iterator();
while (iterA0.hasNext()) {
    Person A = iterA.next();
    iterA1 = A.iterator();
    while (iterA1.hasNext()){
        Person B = iterA1.next();
        A.getsDrunkAndRegretsHookingUpWith(B);
    }
}

那要编码很糟糕,对吧?我该如何适当地执行这个嵌套迭代?

4 个答案:

答案 0 :(得分:4)

您可以同时多次迭代同一个列表,只要它在任何迭代期间都没有被修改。例如:

List<Person> people = ...;
for (Person a : people) {
    for (Person b : people)
        a.getsDrunkAndRegretsHookingUpWith(b);
}

只要getsDrunkAndRegretsHookingUpWith方法不会更改people列表,这一切都很好。

答案 1 :(得分:2)

这是经典握手问题的一个例子。在一个满n人的房间里,n选择2种不同的握手。你无法避免二次运行时。

@Chris' answer向您展示了更好的代码编写方式。


Re:OP评论

  

我一直在做的是一些代码,其中一个事件导致粒子爆炸,导致所有附近的粒子爆炸......链式反应。对象存储在一个列表中,如果非爆炸粒子位于爆炸粒子的定义半径范围内,则它们仅会爆炸。所以我可以调整一些条件来使它更快一点,但仍然需要n ^ 2遍历。

您应使用列表来存储粒子。如果您在2维中建模粒子,请使用quadtree。如果是3维,则为octree

答案 2 :(得分:0)

  

那要编码很糟糕,对吧?

大多数人可能会同意,如果您使用的是Java 5+,并且没有特别需要公开迭代器对象,那么您应该使用“for each”循环来简化代码。但是,这应该对性能没有影响,当然也不会对复杂性产生影响。

不必要地暴露迭代器肯定不是可怕的编程。在1到10的不良编码风格的范围内,这只是1或2.(并且任何告诉你的人最近都没有看到任何真正可怕的编码......)

  

那么如何自己做n ^ 2?

你原来的问题过于设计,无法回答这个问题。

根据真实关系的含义,您可以利用对称性/反对称性或关联性来减少工作量。

但是,如果没有该信息(或其他域信息),您无法改进此解决方案。


对于您的真实示例(涉及粒子),您可以通过将屏幕划分为区域来避免O(N^2)比较问题;例如使用四叉树。然后迭代相同和相邻区域中的点。

答案 3 :(得分:0)

如果在您的情况下,可以减少迭代次数:

  • A.getsDrunkAndRegretsHookingUpWith(B)也暗示B.getsDrunkAndRegretsHookingUpWith(A)
  • 所有元素
  • A.getsDrunkAndRegretsHookingUpWith(A)始终相同

然后代替使用迭代器或foreach,您可以采用更传统的方法并排除与自身的碰撞,并且已经进行了带有withc比较的元素。

List<Person> people;
for (int i=0; i<people.size(); i++){
    a = people.get(i);
    for (int j=i+1; j<people.size();j++){ // compare with next element and onwards in the list
        a.getsDrunkAndRegretsHookingUpWith(people.get(j)); // call method
    }
}