Reputation: 3
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
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
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
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