crazydog
crazydog

Reputation: 3

Kotlin error "Index Out Of Bounds Exception"

I'm newbie to Kotlin, and new to programming also, so pls be gentle :)

Let's say I have a string (it was optimized to NOT have any duplicated character), i want to compare all characters in that string to the alphabet, which declared as a mutable List of character. I want to delete any character from the alphabet which show up in the string. My code is as below

var alphabet=mutableListOf('a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z') 
    var key="keyword"
    println(key)    
    for (i in key.indices)
        {for (j in alphabet.indices)
             {if (key[i] == alphabet[j])
                  alphabet.removeAt(j)     // 1. this line have error
                  //print(alphabet[j])  //2. but this line runs fine
}}}

In above code, I have error at the "alphabet.removeAt(j)" command, so I try another command to print out the characters instead of delete them, and it runs fine. I read some articles and I know this error related to the invalid index, but I used the "indices" key and I think it's pretty safe. Pls help

Upvotes: 0

Views: 4077

Answers (3)

broot
broot

Reputation: 28470

It is safe to iterate using alphabet.indices, but it is not safe to iterate over a collection while modifying it. Note that indices returned indices for a full alphabet, but then you removed some items from it, making it shorter, so indices are no longer valid.

You don't need to iterate over a collection to find an item to remove. You can just do:

alphabet.remove(key[i])

But honestly, you don't need to do anything of this. Your problem is really a subtracting of two sets and you can solve it much easier:

('a'..'z').toSet() - "keyword".toSet()

Upvotes: 2

Sweeper
Sweeper

Reputation: 275160

but I used the "indices" key and I think it's pretty safe

Well, the indices collection is only evaluated once when a loop is entered, not at the start of each iteration. Even if you change the size of alphabet in the inner loop, the inner loop will still loop the same number of times, because it doesn't evaluate alphabet.indices again. It would only do that again on the next iteration of the outer loop, but your code would throw an exception before that point.

Other than decreasing j whenever you remove an item, you can also solve this by

key.forEach(alphabet::remove)

Upvotes: 1

Michael
Michael

Reputation: 58517

You could simplify that whole loop to just:

alphabet.retainAll{ it !in key })

or

alphabet.retainAll { !key.contains(it) }

or if you want the filtered list to be a new list rather than doing it in-place:

val filtered = alphabet.filter { it !in key }

Upvotes: 1

Related Questions