Print position of spaces

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)

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

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