user1243091
user1243091

Reputation: 185

How to convert a List(List[String]) into a Map[String, Int]?

I have a List(List("aba, 4"), List("baa, 2"))and I want to convert it into a map:

val map : Map[String, Int] = Map("aba" -> 4, "baa" -> 2)

What's the best way to archive this?

UPDATE:

I do a database query to retrieve the data: val (_, myData) = DB.runQuery(...)

This returns a Pair but I'm only interested in the second part, which gives me:

myData: List[List[String]] = List(List(Hello, 19), List(World, 14), List(Foo, 13), List(Bar, 13), List(Bar, 12), List(Baz, 12), List(Baz, 11), ...)

Upvotes: 1

Views: 2120

Answers (4)

Frank
Frank

Reputation: 10571

Yet another take:

List(List("aba, 4"), List("baa, 2")).
  flatten.par.collect(
    _.split(",").toList match {
      case k :: v :: Nil => (k, v.trim.toInt) 
  }).toMap

Differences to the other answers:

  • uses .par to parallelize the creation of the pairs, which allows us to profit from multiple cores.
  • uses collect with a PartialFunction to ignore strings that are not of the form "key, value"

Edit: .par does not destroy the order as the answer state previously. There is only no guarantee for the execution order of the list processing, so the functions should be side-effect free (or side-effects shouldn't care about the ordering).

Upvotes: 4

huynhjl
huynhjl

Reputation: 41646

scala> val pat = """\((.*),\s*(.*)\)""".r
pat: scala.util.matching.Regex = \((.*),\s*(.*)\)

scala> list.flatten.map{case pat(k, v) => k -> v.toInt }.toMap
res1: scala.collection.immutable.Map[String,Int] = Map(aba -> 4, baa -> 2)

Upvotes: 8

Adam Rabung
Adam Rabung

Reputation: 5224

List(List("aba, 4"), List("baa, 2")).
  flatten.     //get rid of those weird inner Lists
  map {s=> 
    //split into key and value
    //Array extractor guarantees we get exactly 2 matches
    val Array(k,v) = s.split(","); 
    //make a tuple out of the splits
    (k, v.trim.toInt)}.
  toMap  // turns an collection of tuples into a map

Upvotes: 1

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340733

My take:

List(List("aba, 4"), List("baa, 2")) map {_.head} map {itemList => itemList split ",\\s*"} map {itemArr => (itemArr(0), itemArr(1).toInt)} toMap

In steps:

List(List("aba, 4"), List("baa, 2")).
  map(_.head).                                    //List("aba, 4", "baa, 2")
  map(itemList => itemList split ",\\s*").        //List(Array("aba", "4"), Array("baa", "2"))
  map(itemArr => (itemArr(0), itemArr(1).toInt)). //List(("aba", 4), ("baa", 2))
  toMap                                           //Map("aba" -> 4, "baa" -> 2)

Your input data structure is a bit awkward so I don't think you can optimize it/shorten it any further.

Upvotes: 1

Related Questions