Dan
Dan

Reputation: 23

Converting List to Map using keys in Scala

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

  1. Starts with a key
  2. has some number of non-keys (> 0) between each key
  3. Does not end with a key

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

Answers (3)

Rok Kralj
Rok Kralj

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

Nyavro
Nyavro

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

The Archetypal Paul
The Archetypal Paul

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

Related Questions