2

I have a list of lists of Integer that I'm using to build chains based on an input file. The input specifies pairs (e.g. "3, 1" indicates that 1 replaces 3 in the application), and there are overlaps in the pairs (e.g. "3, 1" and "1, 4" would mean that 1 replaces 3 and 4 replaces 1, so ultimately, 4 replaces 3).

In order to reduce all of the pairs into their final chains, I have a list containing lists of all the pairs, and then I find which entries in the list overlap and append to the chains as needed, removing the pair that has been appended to another. This is how I am attempting to do this, but I know the failure is in doubling up the iterator references:

    for (ArrayList<Integer> outerChain : chains) {
        for (ArrayList<Integer> innerChain : chains) {
            if (outerChain.get(0).equals(innerChain.get(innerChain.size() - 1))) {
                outerChain.remove(0);
                innerChain.addAll(outerChain);
                chains.remove(outerChain);
                break;
            }
        }
    }

As an example of the input/desired output from this operation:

    {<1,3>,<2,7>,<7,9>,<8,12>,<9,1>,<6,8>}

being individual lists corresponding to input pairs, the output would be:

    {<2,7,9,1,3>,<6,8,12>}

Is there a way I can nest iterators like this such that the references within each iterator are updated when removing or updating for one or the other?

Thanks in advance for the help!

4

4 回答 4

4

So when should you use the for-each loop? Any time you can. It really beautifies your code. Unfortunately, you cannot use it everywhere. Consider, for example, the expurgate method. The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it. Finally, it is not usable for loops that must iterate over multiple collections in parallel. These shortcomings were known by the designers, who made a conscious decision to go with a clean, simple construct that would cover the great majority of cases.

(the For-Each Loop)

You shouldn't use the for-each loop when you remove elements from the list or array while traversing it. Therefore you should use the explicit iterator syntax in your case.

Something like this :

Iterator<ArrayList<Integer>> outer = chains.iterator ();
while (outer.hasNext ()) {
    ArrayList<Integer> outerChain = outer.next();
    Iterator<ArrayList<Integer>> inner = chains.iterator ();
    while (inner.hasNext ()) {
        ArrayList<Integer> innerChain = inner.next();
        if (outerChain.get(0).equals(innerChain.get(innerChain.size() - 1))) {
            outerChain.remove(0);
            innerChain.addAll(outerChain);
            outer.remove();
            break;
        }
    }
}
于 2013-04-29T19:58:01.673 回答
1

Once you modify a list in an iterator you can't use that iterator. Fortunately you need to start again anyway so you have a natural solution

OUTER: while(chains.size() > 1) {
    for (ArrayList<Integer> outerChain : chains) {
            for (ArrayList<Integer> innerChain : chains) {
                if (outerChain.get(0) == innerChain.get(innerChain.size() - 1)) {
                    outerChain.remove(0);
                    innerChain.addAll(outerChain);
                    chains.remove(outerChain);
                    continue OUTER;
                }
            }
        }
    break; // no more matches found.
}
于 2013-04-29T19:37:14.520 回答
1

I do not see any problem with double for-each-loops, but I see a big problem with == operator, which you are using for comparing Integer objects. This is totally incorrect. You should use .equals() method instead.

于 2013-04-29T19:38:40.777 回答
-1

use this as a guide:

    for(int[] i: sampleIntArray)
    {
        for(int current: i)
        {
            //sample code here;
        }
    }
于 2016-01-05T14:55:10.123 回答