Reputation: 23
I am struggling with finding an elegant FP approach to solving the following problem in Scala:
Say I have a set of candidate keys
val validKeys = Set("key1", "key2", "key3")
And a list that
For example:
val myList = List("key3", "foo", "bar", "key1", "baz")
I'd like to transform this list into a map by choosing using valid keys as the key and aggregating non-keys as the value. So, in the example above:
("key3" -> "foo\nbar", "key1" -> "baz")
Thanks in advance.
Upvotes: 0
Views: 173
Reputation: 48715
Short and simple:
def create(a: List[String]): Map[String, String] = a match {
case Nil => Map()
case head :: tail =>
val (vals, rest) = tail.span(!validKeys(_))
create(rest) + (head -> vals.mkString("\n"))
}
Upvotes: 2
Reputation: 8866
As a first approximation solution:
def group(list:List[String]):List[(String, List[String])] = {
@tailrec
def grp(list:List[String], key:String, acc:List[String]):List[(String, List[String])] =
list match {
case Nil => List((key, acc.reverse))
case x :: xs if validKeys(x) => (key, acc.reverse)::group(x::xs)
case x :: xs => grp(xs, key, x::acc)
}
list match {
case Nil => Nil
case x::xs => grp(xs, x, List())
}
}
val map = group(myList).toMap
Another option:
list.foldLeft((Map[String, String](), "")) {
case ((map, key), item) if validKeys(item) => (map, item)
case ((map, key), item) =>
(map.updated(key, map.get(key).map(v => v + "\n" + item).getOrElse(item)), key)
}._1
Upvotes: 0
Reputation: 41749
Traversing a list from left to right, accumulating a result should suggest foldLeft
myList.foldLeft((Map[String, String](), "")) {
case ((m, lk), s) =>
if (validKeys contains s)
(m updated (s, ""), s)
else (m updated (lk, if (m(lk) == "") s else m(lk) + "\n" + s), lk)
}._1
// Map(key3 -> foo\nbar, key1 -> baz)
Upvotes: 1