Reputation: 527
I have an arbitrarily nested Map[String, Any]
that I want to traverse and update values given a certain path.
For example, if the nested Map
is
Map("a" -> "1", "b" -> Map("c" -> "2"))
and the path is ["b", "c"]
I expect the result to be
Map("a" -> "1", "b" -> Map("c" -> "null"))
What I've tried so far is
def updateMapValue(
map: Map[String, Any],
path: List[String]
): Map[String, Any] =
map map {
case (k: String, v: String) =>
if (k.contains(path.head)) k -> "null"
else k -> v
case (k: String, v: Map[String @unchecked, _]) => updateMapValue(v, path.tail)
}
but the compilation error I get here is
Expression of type Iterable[Equals] doesn't conform to expected type Map[String, Any]
which happens when I try to call updateMapValue
recursively.
What is happening here and is there an easier way to traverse nested Map
s?
Upvotes: 2
Views: 504
Reputation: 22635
You've got several problems with your code. First of all, you're using head
which would throw an exception in the case, there is no head on path list (and it would happen if you passed the wrong path to the method).
Secondly, here case (k: String, v: Map[String, _]) => updateMapValue(v, path.tail)
you're returning map, with wrong type, you probably meant k -> updateMapValue(v, path.tail)
.
Here's my implementation:
def updateMapValue(
map: Map[String, _],
path: List[String]
): Map[String, _] = {
path match { //we iterated over path getting head
case x :: xs => map.map {
case `x` -> (m: Map[String, _]) => x -> updateMapValue(m, xs) //if value is map go deeped
case `x` -> (_: String) => x -> "null" //if value is String replace with "null"
case w => w
}
case Nil => map
}
}
val m = Map("a" -> "1", "b" -> Map("c" -> "2"))
val path = List("b", "c")
updateMapValue(m, path) //Map(a -> 1, b -> Map(c -> null))
This method is not stack-safe, because it's not tail-recursive, but if you know your maps won't be very deep it should do the job. You can make it stack-safe with TailCalls though.
Upvotes: 2