yarchik
February 10, 2022, 8:59am
1
Given a string, determine the positions of spaces. I would like to avoid loops and use functional style
val name = " 1 3 678"
val char: Char = ' '
val indexSpaces: Array[Int] = name.zipWithIndex.filter((x) => x._1 == char).map((x) => x._2).toArray
println(indexSpaces.mkString("; "))
It works, but I seems to overcomplicate the things. What is the idiomatic way? What is the shortest functional way?
I also tried the following
var arraySpaces: Array[Int] = name.zipWithIndex collect {case x if x._1 == char => x._2}.toArray
println(arraySpaces.mkString("; "))
But it gives me
The argument types of an anonymous function must be fully known.
Why in the first code toArray
works, but not in the second code?
I don’t know, it’s easier to share scastie or transcripts.
Welcome to Scala 2.13.8 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.
scala> val s = " 1 3 678"
val s: String = " 1 3 678"
scala> s.iterator
val res0: Iterator[Char] = <iterator>
scala> .zipWithIndex
val res1: Iterator[(Char, Int)] = <iterator>
scala> .collect { case (c, i) if c == ' ' => i }
val res2: Iterator[Int] = <function1>
scala> .toArray
val res3: Array[Int] = Array(0, 2, 4, 5)
yarchik
February 10, 2022, 10:42am
3
It would be better if you share the full code fine, not the interactive session.
@yarchik I believe it’s because you are mixing the dot notation, with the infix notation (with collect
), in a long chain. For example this works
scala> name.zipWithIndex.collect{case x if x._1 == char => x._2}.toArray
val res10: Array[Int] = Array(0, 2, 4, 5)
Is this OK? What do you think?
scala> (for (c, i) <- name.zipWithIndex if c == char yield i).mkString("; ")
val res9: String = 0; 2; 4; 5
Alternately, going from your earlier solution but a bit more sugared:
scala> name.zipWithIndex.filter(_._1 == char).map(_._2).mkString("; ")
val res14: String = 0; 2; 4; 5
2 Likes
yarchik
February 10, 2022, 12:55pm
5
Nice, I learnt new things from your post.
1 Like
The best way would be to use collect
and use proper pattern matching syntax, also rather return a List
or a Vector
rather than an Array
val spaces: List[Int] =
name.zipWithIndex.collect {
case (' ', idx) => idx
}.toList
println(spaces.mkString("; "))
2 Likes