1

I have this for loop:

for (int i = 0; i < textParsed.size(); ++i) {
    String element = textParsed.get(i); 
    int readString = 0;

    while (savedInput.contains(element)) {
        textPositions.add(savedInput.indexOf(element, readString), i);
        readString += savedInput.indexOf(element) + element.length();
    }
}

Where:

  • textPositions is an ArrayList<Integer>
  • textParsed is an ArrayList<String>

It's intended to change textPositions so that the Strings stored in textParsed are represented within that ArrayList as numbers.

An example, textParsed:

["hello", "hi-"]

with the String:

"hello everyone, hi-hello, it's great to be here, hi-"

should result in a textPositions of something like:

[0, ... , 1, 0, ... , 1]

Hopefully that makes sense.

I'm getting an IndexOutOfBoundsException when I try to use the .add() method. As far as I can tell, this should be impossible. Here's the exception:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 29, Size: 1
at java.util.ArrayList.rangeCheckForAdd(ArrayList.java:612)
at java.util.ArrayList.add(ArrayList.java:426)

Thanks for any help you can offer.

Mr. Polywhirl
  • 31,606
  • 11
  • 65
  • 114
JimmyM
  • 357
  • 3
  • 17
  • `++i` should be `i++`. Read [explain working of post and pre increment operator in Java](http://stackoverflow.com/questions/2371118/explain-working-of-post-and-pre-increment-operator-in-java) – Smit Dec 11 '13 at 23:42
  • 1
    Why would it be impossible? You're using `savedInput.indexOf` which is presumably returning 29, when your array list has a size of 1... – Jon Skeet Dec 11 '13 at 23:42
  • @Smit: No, that's completely irrelevant in this context. – Jon Skeet Dec 11 '13 at 23:43
  • @JonSkeet Sorry didnt paid much attention to stacktrace. But it could still cause `IndexOutOfBoundsException` – Smit Dec 11 '13 at 23:43
  • @JonSkeet This is what I'm trying to understand. As far as I'm aware, add should automatically resize the ArrayList, no? I can't find any other way of resizing an ArrayList - every reference I find says it should automatically resize. – JimmyM Dec 11 '13 at 23:47
  • @Smit: No, it couldn't. In this context, `i++` and `++i` are synonymous, because the *result* of the expression isn't being used. The effect of "`i` is incremented" is the same in both cases. – Jon Skeet Dec 11 '13 at 23:47
  • 1
    @user1626141: No, it shouldn't. Read the documentation for `ArrayList.add`, in particular the circumstances under which is throws an exception. `ArrayList.add` will always expand the size of the list by exactly 1, inserting the element at the right place. You can't just use it to add a load of entries at once. – Jon Skeet Dec 11 '13 at 23:52
  • That's incredibly irritating, I guess I'll just have to create an array of the same size as the String input. Thanks for the answer! – JimmyM Dec 11 '13 at 23:59
  • 1
    @user1626141: That's probably what you want anyway - as otherwise any time you added an entry before existing ones, it would have pushed existing entries, changing their indexes... Alternatively, use a `Map` with an `Integer` as the key. – Jon Skeet Dec 12 '13 at 00:02
  • 2
    Possible duplicate of [ArrayList initial capacity and IndexOutOfBoundsException](http://stackoverflow.com/questions/11908037/arraylist-initial-capacity-and-indexoutofboundsexception) – Raedwald Jan 02 '16 at 13:55

1 Answers1

3

Your main problem is the ArrayList only automatically resizes if the element is already within the bounds of the internal array. If the array only contains one element, you can only ArrayList#add(int, E) at element 0. But if the maximum size is known you can create the list based on that.

ArrayList<Integer> textPositions = new ArrayList<Integer>(savedInput.length());

for (int i = 0; i < savedInput.length(); i++)
    textPositions.add(null);

Remember, ArrayList is a List abstraction so the idea is not to be "sparse". It is basically not meant for this, it is designed to span from a beginning to an end and be appendable. ArrayList's size and indexing is based on the number of times it's been added to and not the length of its internal array. Also note that if the final length is anticipated, it's always better to create the list with the initial size so it doesn't have to resize itself. (Or just use an array!)

Furthermore, you have a few other problems. The first is that add inserts an element, shifting all others to make room. I don't think that's what you want. I think you want to use set. The other is that your while loop is an infinite loop because if a String contains a substring once, it will always continue to contain it unless it becomes a different String. : )

int[] textPositions = new int[savedInput.length()];

for (int i = 0; i < textParsed.size(); ++i) {
    String element = textParsed.get(i); 
    int readString = 0;

    int indexOfElement;

    while ((indexOfElement = savedInput.indexOf(element, readString)) > -1) {
        textPositions[indexOfElement] = i;
        readString = indexOfElement + element.length();
    }
}

You should also consider using a Map for this sort of thing, especially if the data is large, like if you were generating an index for a textbook.

Radiodef
  • 35,285
  • 14
  • 78
  • 114
  • Thanks for a thorough answer - the `while` loop I posted was supposed to work more like your example, but unfortunately I pasted an intermediate state rather than the final version. The final version still had a bug, so I appreciate your loop! The rest of the answer is a fantastic explanation of my misunderstandings of ArrayLists, thanks very much. – JimmyM Dec 12 '13 at 19:14