开发者

Is it okay to iterate over a list within another iteration of the same list?

I have some objects in an ArrayList, and I want to perform collision detection and such. Is it okay to do something like:

List<Person> A;
iterA0 = A.iterator();
while (iterA0.hasNext()) {
    Person A = iterA.next();
    iterA1 = A.iterator();
    while (iterA1.hasNext()){
        Person B = iterA1.next();
        A.getsDrunkAndRegretsHookingUpWit开发者_高级运维h(B);
    }
}

That's gotta be terrible coding, right? How would I perform this nested iteration appropriately?


You can iterate over the same list multiple times concurrently, as long as it's not being modified during any of the iterations. For example:

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

As long as the getsDrunkAndRegretsHookingUpWith method doesn't change the people list, this is all fine.


This is an example of the classic handshake problem. In a room full of n people, there are n choose 2 different possible handshakes. You can't avoid the quadratic runtime.

@Chris' answer shows you a better way to code it.


Re: OP comment

What I've been cooking up is some code where an event causes a particle to explode, which causes all nearby particles to explode...chain reaction. The objects are stored in one list and the non-exploded particles only explode if they are within a defined radius of an exploding ones. So I could dish up some conditionals to make it a bit faster, but still need the n^2 traversal.

You should not use a list to store the particles. If you're modeling particles in 2 dimentions, use a quadtree. If 3 dimensions, an octree.


Number of iterations can be reduced if in you case:

  • A.getsDrunkAndRegretsHookingUpWith(B) implies B.getsDrunkAndRegretsHookingUpWith(A) too,
  • and A.getsDrunkAndRegretsHookingUpWith(A) will always be same for all elements

then instead of using iterator or foreach, you can take more traditional approach and exclude collision with itself and with the elements with withc comparison has already taken place.

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


That's gotta be terrible coding, right?

Most people would probably agree that if you were using Java 5+, and there was no particular need to expose the iterator objects, then you should simplify the code by using a "for each" loop. However, this should make no difference to the performance, and certainly not to the complexity.

Exposing the iterators unnecessarily is certainly not terrible programming. On a scale of 1 to 10 of bad coding style, this is only a 1 or 2. (And anyone who tells you otherwise hasn't seen any truly terrible coding recently ... )

So how to do n^2 over oneself?

Your original question is too contrived to be able to give an answer to that question.

Depending on what the real relation is, you may be able to exploit symmetry / anti-symmetry, or associativity to reduce the amount of work.

However, without that information (or other domain information), you can't improve on this solution.


For your real example (involving particles), you can avoid the O(N^2) comparison problem by dividing the screen into regions; e.g. using quadtrees. Then you iterate over points in the same and adjacent regions.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜