As title is saying, I want to implement a function, pool which returns a List of character after removing all the elements of given string which are the same letters in the same index as the another string. It gives me an StringIndexOutOfBoundsExceptions due to the code I wrote for getting an element in the given index. How can I solve this?
My implementation
def pool(secret: String, word: String) : List[Char] = {
secret.filterNot(x => secret.apply(x) == word.apply(x)).toList
}
Test Cases
pool("chess", "caves") => List(h, e, s)
pool("chess", "swiss") => List(c, h, e)
Error Message
java.lang.StringIndexOutOfBoundsException: String index out of range: 99
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
at java.base/java.lang.String.charAt(String.java:1515)
at scala.collection.StringOps$.apply$extension(StringOps.scala:188)
at $anonfun$pool$1(<console>:3)
at $anonfun$pool$1$adapted(<console>:3)
at scala.collection.StringOps$.filterNot$extension(StringOps.scala:1264)
at pool(<console>:3)
... 32 elided
CodePudding user response:
x
is a character, String.apply
accepts an index. c
has acii code 99, so when you do "caves".apply('c')
it tries to access a character in "caves" at index 99, and throws, because the string isn't long enough.
If you insist on using the actual index, something like this might work:
secret.zipWithIndex.collect { case (c, i) if word(i) != c => c }.mkString
But this will still throw if word
happens to be shorter than secret
. You can add another condition to guard against that if you like (case (c,i) if i >= word.length || word(i) != c => c)
, but something like this would be somewhat more readable and idiomatic (direct index access is generally frowned upon in scala, because it can often lead to subtle performance problems, and causes the reader to spend extra cycles in order to prove that it is legitimate in a given case):
secret
.iterator
.zipAll(word, 0.toChar, 0.toChar)
.collect { case (a,b) if a != b && a != 0.toChar => a }
.mkString