1

I have a Map[String, String].

Edit: val m: Map[String, Any] = Map("a" -> Map("b" -> Map("c" -> "e", "d" -> "g")))

Is there a way to convert my Map[String,Any] to Map[String,String]

What is the best way to convert this nested Map into another Map with values like

Map("a.b.c" -> "e", "a.b.d" -> "g")

I found an earlier solution that is for Map[String,Int]. The link is given here: How to make a nested map as dot separated strings of key and value in scala

I tried to change the code (given in the comments of the above question):

def traverse(el: String, acc: List[String] = List.empty[String]): Map[String, String] = el match {
  case leaf: String => Map(acc.reverse.mkString(".") -> leaf)
  case m: Map[String, String] => m flatMap {
    case (k, v) => traverse(v, k :: acc)
  }
}

traverse(m)

However, i get the following error: Scrutinee is incompatible with pattern type, found: Map[String, String], required: String

I am new to Scala, so am unable to modify the code, please suggest what is causing this.

Update Solution:

def unravel(badmap :Map[String,_]
          ,key:List[String] = Nil) :Map[String,String] =
badmap.foldLeft(Map.empty[String,String]){
  case (m,(k,v)) if v.isInstanceOf[Map[_,_]] =>
    println("Case1" + m)
    m ++ unravel(v.asInstanceOf[Map[String,_]], k::key)
  case (m,(k,v)) =>
    println("Case2: " + m)
    val tempv = if (v!=null) v.toString  else null
    m + ((k::key).reverse.mkString(".") -> tempv )
}

I had a null value which caused it to fail. I updated the solution given. Thank you!

5
  • case m: Map[String, Any] is what you need to keep for the pattern match. Commented Jun 13, 2020 at 5:29
  • So, I would have to change my Map[String, String] to Map[String,Any]? Commented Jun 13, 2020 at 5:31
  • the example map prints as Map(a -> Map(b -> Map(c -> e, d -> g))). I need it to be changed to a.b.c -> e @jwvh Commented Jun 13, 2020 at 5:58
  • Hi, i have made the change Commented Jun 13, 2020 at 6:25
  • 1
    Map[String, Any] smells like json, you may be better using a better tool for handling such data type. Commented Jun 13, 2020 at 13:48

1 Answer 1

1

You're in a bad place (type Any).

Sometimes we have to use unwise and unsafe tools (runtime type casting) to get out of a bad situation.

def unravel(badmap :Map[String,_]
           ,key:List[String] = Nil) :Map[String,String] =
  badmap.foldLeft(Map.empty[String,String]){
    case (m,(k,v)) if v.isInstanceOf[Map[_,_]] =>
      m ++ unravel(v.asInstanceOf[Map[String,_]], k::key)
    case (m,(k,v)) =>
      m + ((k::key).reverse.mkString(".") -> v.toString)
  }

testing:

val m: Map[String, _] =
  Map("a" -> Map("b" -> Map("c" -> "e", "d" -> "g")))

unravel(m)
//res0: Map[String,String] = Map(a.b.c -> e, a.b.d -> g)

Much better to avoid situations like this. Go back and fix the code that produced that Map.

Sign up to request clarification or add additional context in comments.

2 Comments

Quick doubt. Now if my code returns Map[String,_] would this problem be more efficient? If yes, can you please tell me if this same unravel function would still work?
So, above I had given a sample map. The actual map i have prints like this: Map(keyA -> Map(keyB -> valB, keyC -> keyC, keyD -> Map(keyE -> valE, keyF -> valF), keyG -> null)) The Map is of type Map[String,_]. When I run this above unravel function, I get null pointer exception.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.