Convert a String with comma separated latitudes and longitudes to a Seq[Coordinate]

I have a function that receives a String like the following:

"-10.0 -10.0,10.0 10.0,0.0 0.0"


And needs to translate that into a Seq[Coordinate] that would look like this:

Seq(
Coordinate(-10.0, -10.0),
Coordinate( 10.0,  10.0),
Coordinate(  0.0,   0.0)
)


Here is the function that I wrote to achieve this:

def toCoordinates(coordinates: String): Seq[Coordinate] = {
val coordinatesList = coordinates.split(",")
coordinatesList flatMap { coordinate =>
coordinate.split("\\s+") match {
case Array(lat:String, lon:String) => Some(Coordinate(lat.toDouble, lon.toDouble))
case _                             => None
}
}
}


I see that if someone sends "foo bar" as a coordinate, my code would fail miserably, although I don't see a way to prevent this without some if conditions.

Any idea on how I can implement this check while still having functional code? Or any other tips that might be helpful for a Scala newbie.

Instead of writing lat.toDouble and lon.toDouble, I would use s.split("\\s+").map(_.toDouble) to convert all elements. The type annotation within the match seems excessive to me here.

To discard invalid coordinates such as "foo bar", you would have to catch a NumberFormatException.

Note that split("\\s+") is not tolerant of spaces after commas. For example, " 1.0 2.0".split("\\s+") would produce Array("", "1.0", "2.0"), which would be a three-element array and thus considered invalid.

def toCoordinates(ss: String): Seq[Coordinate] = {
ss.split(",").flatMap { s =>
try {
s.split("(?<!^)\\s+").map(_.toDouble) match {
case Array(lat, lon) => Some(Coordinate(lat, lon))
case _               => None
}
} catch {
case e: NumberFormatException => None
}
}
}


Also you can write more human-readable and understandable algorithm with the help of extractors and method collect:

val Coord = """(.+?)\s+(.+)""".r

object Double { def unapply(s: String) = Try(s.toDouble).toOption }

def parseCoordinates(input: String): Seq[Coordinate] =
input.split(',') collect {
case Coord(Double(lat), Double(lan)) => Coordinate(lat, lan)
}

• what does that .r do? The one on the definition of Coord – Rodrigo Sasaki Jul 18 '16 at 18:50
• Method .r creates regular expression (instance of Regex class). "abc".r is equivalent to new Regex("abc"). See description and usage here. – Nikolay Artamonov Jul 20 '16 at 11:48