Home > Mobile >  Filter the string removing all elements which have the same element as in another string in the same
Filter the string removing all elements which have the same element as in another string in the same

Time:01-18

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
  • Related