0

So I have 2 arraylists (player1List, and player2List) each of which have 26 ints in them. I run them through a for-loop comparing two numbers from each. If one list has a number that is bigger than the other, the smaller number gets added to the winning list. However, when I run it through the for-loop at a certain point I get an "indexOutOfBoundsException: Index 21: Size 21." How do I get to run through the loop until one of the arraylists is empty? Here is my code.

    for (int i = 0; i < player1List.size; i++){
        if (player1List.get(i) < player2List.get(i)){
            System.out.printf("Player 1: %d\n", player1List.get(i));
            System.out.printf("Player 2: %d\n", player2List.get(i));
            System.out.printf("Player 2 wins round!\n");
            player2List.add(player1List.get(i));
            player1List.remove(player1List.get(i));
        }
        if (player1List.get(i) > player2List.get(i)){
            System.out.printf("Player 1: %d\n", player1List.get(i));
            System.out.printf("Player 2: %d\n", player2List.get(i));
            System.out.printf("Player 1 wins round!\n");
            player1List.add(player2List.get(i));
            player2List.remove(player2List.get(i));
        }
        if (player1List.get(i) == player2List.get(i)){

            System.out.printf("Player 1: %d\n", player1List.get(i));
            System.out.printf("Player 2: %d\n", player2List.get(i));
            System.out.printf("It's a tie, cards return to your deck.\n");

        }
        if (player1List.isEmpty()){
        System.out.printf("Player 2 wins the game.\n");
        break;
        }
        if (player2List.isEmpty()){
        System.out.printf("Player1 wins the game.\n");
        break;
        }
        }

I have asked a similar question to this, however, this is more narrowed down to what I need.

B-M281
  • 11
  • 2
  • 4
  • 1
    The second answer to your previous question explains why there is a problem with removing items from a list inside a loop. – assylias Mar 19 '12 at 22:41
  • You could write a helper method that checks a certain index "safely", and then returns -1 or something if the index doesn't exist. – Mike Christensen Mar 19 '12 at 22:42
  • `player1List.get(i) == player2List.get(i)` can cause your issue because in the previous blocks, you may have removed the last item of a list and then you try to access it. – Guillaume Polet Mar 19 '12 at 22:45
  • Why not use plain arrays in this case with a1[i]=a2[i]? – 01es Mar 19 '12 at 23:05
  • because I can't shorten or lengthen the size of an array after it has already been created. – B-M281 Mar 19 '12 at 23:15

3 Answers3

1

If you need intermediate additions to the collection to matter in the next iteration, then you need to make sure your indexes are correct. Hold two counters. When removing - do not increment. Check if the list is not bigger than the current index.

As you can see - removing and adding while iterating makes things more complex when indexes are concerned. That's why a better solution would be to use iterators:

Iterator<Foo> it1 = list1.iterator();
Iterator<Foo> it2 = list2.iterator();

while(it1.hasNext() && it2.hasNext()) {
   Foo foo1 = it1.next();
   Foo foo2 = it2.next();
   if (..) {
       it2.remove();
   }
}

When you need to add to one of the collections, add to a new collection instead, that does not interfere in the iteration.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • +1 Also refer question http://stackoverflow.com/questions/1196586/calling-remove-in-foreach-loop-in-java – 01es Mar 19 '12 at 22:47
  • Two iterators is a great deal of overhead when one will do the trick. – kasavbere Mar 19 '12 at 22:50
  • one won't work. An iterator has only one underlying collection – Bozho Mar 19 '12 at 22:54
  • The lists are being modified within the loop, so iterators won't work! It must be index-based. – Manish Mar 19 '12 at 23:08
  • @Manish - removing via the iterator is allowed. And I noted that if addition is required to affect the iteration, then indexes should be used. But otherwise iterators are better. – Bozho Mar 19 '12 at 23:10
  • @Bozho If you read the question, addition _is_ required. It's about transferring items from one list to another. – Manish Mar 19 '12 at 23:31
0
int size = list2.size()>list1.size()?list1.size():list2.size();
for(int i=0; i<size;i++){
   ...//do all your work here.

  size = list2.size()>list1.size()?list1.size():list2.size();//last line in loop
}

because you are modifying your lists (i.e. removing elements), you should continuously check your limit; hence the last line in the loop.

kasavbere
  • 5,873
  • 14
  • 49
  • 72
0

Here we go:

ArrayList<Integer> a = new ArrayList<Integer>(
    Arrays.asList(new Integer[]{0, 1, 5}));
ArrayList<Integer> b = new ArrayList<Integer>(
    Arrays.asList(new Integer[]{3, 4, 2}));

int sA = a.size();
int sB = b.size();

for (int i = 0, j = 0; i < sA && j < sB; i++, j++) {
  int iA = a.get(i);
  int iB = b.get(j);

  if (iA < iB) {
    b.add(iA);
    a.remove(i--);
    sA--;

  } else if (iA > iB) {
    a.add(iB);
    b.remove(j--);
    sB--;
  }
}

System.out.println("a: " + a);
System.out.println("b: " + b);

Output:

a: [5, 2]
b: [3, 4, 0, 1]

Suppose there are N1 items in the first list and N2 items in the second list, the number of iterations will always be limited to the lesser of N1 and N2. e.g. if N1 is 10 and N2 is 11, there will be at most 10 iterations.

When an item is transferred from one list to the other, we decrement the index counter as well as the total number of items we need to look at for the list from which the item was just removed; we don't care about the list to which the item was added, because it's always added at the end and we'll never get that far in the loop.

Comparisons are between corresponding items in the original lists before they are modified. In the above example, 5 is compared with 2, even though 5 is at the index 0 in the first list and 2 is at the index 2 in the second list by the time the comparison is actually done.

Manish
  • 3,472
  • 1
  • 17
  • 16
  • How would I continue this until one of the lists is empty? Would I use a.. while(!a.isEmpty() && !b.isEmpty()){ //your code } – B-M281 Mar 19 '12 at 23:51
  • @B-M281 You don't have to do anything. `sA` or `sB` will become 0 if one of the lists becomes empty. Try it out with different values to see how it works. – Manish Mar 19 '12 at 23:57
  • But your output shows a as having 2 values in it and b as having 4. If I don't have to do anything, how come yours doesn't continue until one of them is empty? – B-M281 Mar 20 '12 at 00:01
  • @B-M281 `0 < 3`, `1 < 4`, and `5 > 2` (3 iterations), and the loop ends. What output do you expect? Please post the expected output. – Manish Mar 20 '12 at 00:15
  • Well what I want is for it to continually loop until either: ' a: empty b: [5,4,3,2,1,0] or a: [5,4,3,2,1,0] b: empty ' – B-M281 Mar 20 '12 at 00:24
  • I've gotten it where there are 2 values left in a and 50 in b (out of 52 ints). but when one of the decks is empty, it throws an index out of bounds exception. (At least I think it hits an empty deck when that happens. – B-M281 Mar 20 '12 at 00:29
  • I guess what I am asking is how can I get it to print "a is empty" when all the values are in b and there are no more in a. – B-M281 Mar 20 '12 at 00:33
  • Given two lists, `a:[0,1,5]` and `b:[3,4,2]`, what is the expected output? Unless you tell me that, I have no idea what you're looking for. – Manish Mar 20 '12 at 00:36
  • Expected output: `a is empty` (because there are no more integers in a) and b:`[0,1,5,3,4,2]`or vice versa. – B-M281 Mar 20 '12 at 00:40
  • @B-M281 And what is the basis for `b` becoming `[0,1,5,3,4,2]`? `a`'s 5 is greater than `b`'s 2, so `a` must take 2; you're giving `a`'s 5 to `b` instead. Please update your question with more details as to the logic. – Manish Mar 20 '12 at 00:50
  • Well what I am using is a deck of cards with the numbers 2-14 twice in each deck. `a: [2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,2,3,4,5,6,7,8,9,10,11,12,13,14]` and `b: [2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,2,3,4,5,6,7,8,9,10,11,12,13,14]` and I want it to loop until it's like this: `a: [2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,2,3,4,5,6,7,8,9,10,11,12,13,14, 2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,2,3,4,5,6,7,8,9,10,11,12,13,14]`and `b is empty` but the a's numbers in a completely different order of course. I am implementing the card game War. – B-M281 Mar 20 '12 at 00:55
  • @B-M281 Please run my program with `a:[0,0,0]` and `b:[1,1,1]` and you'll get the result as `a:[]` (empty) and `b:[1,1,1,0,0,0]`, and there won't be an "index out of bounds" error. Then read the code, try to learn how it works. That's as much as I can help you here. – Manish Mar 20 '12 at 00:56