reikje
reikje

Reputation: 3064

Scala pattern matching on generic Map

Whats the best way to handle generics and erasure when doing pattern matching in Scala (a Map in my case). I am looking for a proper implementation without compiler warnings. I have a function that I want to return Map[Int, Seq[String]] from. Currently the code looks like:

def teams: Map[Int, Seq[String]] = {
    val dateam = new scala.collection.mutable.HashMap[Int, Seq[String]]

    // data.attributes is Map[String, Object] returned from JSON parsing (jackson-module-scala)
    val teamz = data.attributes.get("team_players")
    if (teamz.isDefined) {
      val x = teamz.get
      try {
        x match {
          case m: mutable.Map[_, _] => {
            m.foreach( kv => {
              kv._1 match {
                case teamId: String => {
                  kv._2 match {
                    case team: Seq[_] => {
                      val tid: Int = teamId.toInt
                      dateam.put(tid, team.map(s => s.toString))
                    }
                  }
                }
              }
            })
          }
        }
      } catch {
        case e: Exception => {
          logger.error("Unable to convert the team_players (%s) attribute.".format(x), e)
        }
      }

      dateam
    } else {
      logger.warn("Missing team_players attribute in: %s".format(data.attributes))
    }
    dateam.toMap
}

Upvotes: 1

Views: 1201

Answers (2)

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297275

Use a Scala library to handle it. There are some based on Jackson (Play's ScalaJson, for instance -- see this article on using it stand-alone), as well as libraries not based on Jackson (of which my preferred is Argonaut, though you could also go with Spray-Json).

These libraries, and others, solve this problem. Doing it by hand is awkward and prone to errors, so don't do it.

Upvotes: 2

iuriisusuk
iuriisusuk

Reputation: 434

It could be reasonable to use for comprehension (with some built in pattern matching). Also we could take into account that Map is a list of tuples, in our case of (String, Object) type. As well we will ignore for this example probable exceptions, so:

import scala.collection.mutable.HashMap

def convert(json: Map[String, Object]): HashMap[Int, Seq[String]] = {

  val converted = for {
    (id: String, description: Seq[Any]) <- json
  } yield (id.toInt, description.map(_.toString))

  HashMap[Int, Seq[String]](converted.toSeq: _*)
}

So, our for comprehension taking into account only tuples with (String, Seq[Any]) type, then combines converted String to Int and Seq[Any] to Seq[String]. And makes Map to be mutable.

Upvotes: 1

Related Questions