Reputation: 1400
I have a string val trackingHeader = "k1=v1, k2=v2, k3=v3, k4=v4"
which I would like to parse and convert it to a Map(k1 -> v1, k2 -> v2, k3 -> v3, k4 -> v4)
. Following is the code I used to do this:
val trackingHeadersMap = trackingHeader
.replaceAll("\\s", "")
.split(",")
.map(_ split "=")
.map { case Array(k, v) => (k, v) }
.toMap
I was able to get my desired output. But, I also need to handle a malformed input case like val trackingHeader = "k1=v1, k2=v2, k3=v3, k4="
. Notice there is no value for key k4
. My above code will start breaking with scala.MatchError: [Ljava.lang.String;@622a1e0c (of class [Ljava.lang.String;)
so I changed it to:
val trackingHeadersMap = trackingHeader
.replaceAll("\\s", "")
.split(",")
.map(_ split "=")
.collect { case Array(k, v) => (k, v) }
.toMap
Great now I have handle the malformed case as well by using collect
but I would like to know what key had this issue and log it (in this example its k4
). I tried the following and was able to get the desired result but I am not sure if its the right way to do it:
val badKeys = trackingHeader
.replaceAll("\\s", "")
.split(",")
.map(_ split "=")
.filterNot(_.length == 2)
Now I can iterate over the badKeys
and print them out. Is there a better way to do this?
Upvotes: 1
Views: 58
Reputation: 40500
You could make the result optional, and use flatMap
instead of map
.flatMap {
case Array(k, v) => Some(k -> v)
case Array(k) => println(s"Bad entry: $k"); None
}
Upvotes: 2
Reputation: 37832
One solution would be to add a map
step that prints the bad key for elements matching a one-element array before the call to collect
:
val trackingHeadersMap = trackingHeader
.replaceAll("\\s", "")
.split(",")
.map(_ split "=")
.map {
case v @ Array(k) => println(s"bad key: $k"); v
case v => v
}.collect {
case Array(k, v) => (k, v)
}
.toMap
A better solution (which separates side-effects from transformations) would be to use partition
which would split this into two collections ("good" and "bad"), and handle each one separately:
val (good, bad) = trackingHeader
.replaceAll("\\s", "")
.split(",")
.map(_ split "=")
.partition(_.length == 2)
val trackingHeadersMap = good.map { case Array(k, v) => (k, v) }.toMap
bad.map(_(0)).foreach(k => println(s"bad key: $k"))
Upvotes: 0