I have a list of strings
val allLines = List("James Bond", "secret agent", "", "Martin Odersky")
I then want "map" that to e.g. a List[Person]
where case class Person(name: String, moreDetails: List[String]
using several elements at once.
val people = allLines.someCombinatorFunction { lines =>
val name = lines.head
val (moreDetails, remainingLines) = lines.span(_ != "")
val person = Person(name, moreDetails)
(person, remainingLines)
}
this should give me:
List(Person("James Bond", List("secret agent")), Person("Martin Odersky", Nil))
Ie. I want to take a variable number lines, combine them to a Person, and "hand off" the remaining lines. List[String] => List[Person]
. This is trivial with recursion:
def linesToPeople(lines: List[String]): List[Person] = { lines =>
val name = lines.head
val (moreDetails, remainingLines) = lines.span(_ != "")
val person = Person(name, moreDetails)
person :: linesToPeople(remainingLines)
}
... but!, recursion is expensive, unless you make it tail-recursive..:
def linesToPeople(lines: List[String], acc: List[Person] = Nil): List[Person] = { lines =>
val name = lines.head
val (moreDetails, remainingLines) = lines.span(_ != "")
val person = Person(name, moreDetails)
linesToPeople(remainingLines, person :: acc)
}
^ This is where it becomes a little too cumbersome imo. You also need to do a .reverse
in the end to get the order right. A combinator would be nice here
So basicly, I have a list, I want to "consume" & combine a variable number of its elements, and return the remains. Is there a way to do this without resorting to recursion?
Scalaz has a function selectSplit
for that:
import scalaz._
import Scalaz._
def getPeople(lines: List[String]): List[Person] =
lines.selectSplit(_ != "").map(l => Person(l.head, l.tail))
And then:
scala> getPeople(List(
"James Bond", "secret agent", "",
"Martin Odersky", "",
"Arnold Schwarzenegger", "Terminator", "governor"))
res8: List[Person] = List(Person(James Bond,List(secret agent)), Person(Martin Odersky,List()), Person(Arnold Schwarzenegger,List(Terminator, governor)))