Convert a Seq["key1=val1"] to a Map[String, String] in Scala - scala

I have the following Seq[String], with all strings with = delimiter.
keysVals = ["Country=France", "City=Paris"]
I would like to convert it into a Map[String, String], such as
result = Map("Country"->"France", "City"->"Paris")
How to do that, please?

The shortest way seems to be
data.map { case s"${k}=${v}" => k -> v }.toMap
using StringContext.s.unapplySeq as in
val data = List("Country=France", "City=Paris")
println(data.map { case s"${k}=${v}" => k -> v }.toMap)
(thanks #Luis Miguel Mejía Suárez).
Alternatively, with Regex pattern-matching:
val KeyValuePattern = "([^=]+)=([^=]+)".r
data.map { case KeyValuePattern(k, v) => k -> v }.toMap
With good old String.split:
data.map(str => str.split("=") match { case Array(k, v) => k -> v }).toMap

Related

How to merge Maps on Keys and combine their values scala [duplicate]

This question already has answers here:
Merge maps by key
(8 answers)
Closed 5 years ago.
I have 2 Maps :
val map1 = Map("col_1" -> "data_1", "col_2" -> "data_2", "col_3" -> "data_3")
val map2 = Map("col_1" -> "myval_1", "col_2" -> "myval_2", "col_3" -> "myval_3")
Required Output:
res = Map("col_1" -> ("data_1", "myval_1"), "col_2" -> ("data_2", "myval_2"),
"col_2" -> ("data_2", "myval_2") )
Basically Keeping the keys of 'map1' & merging values of both maps
Output must be Tuple and not a List or Seq
Use map (throws if one of keys is missing on the other map):
val res = map1.map { case (k, v) => (k, (v, map2(k))) }
Or use collect (skips the keys not present in both maps):
val res = map1.collect { case (k, v) if map2.contains(k) => (k, (v, map2(k))) }
Or with default value for map2:
val res = map1.map { case (k, v) => (k, (v, map2.getOrElse(k, ""))) }
For symmetric case, I'd go with Scalaz version from my other answer
Get all the keys which present in map1 along with the combination which keys present in map2 :
val res = map1.collect { case (k, v) => if (map2.contains(k)) (k, (v, map2(k))) else (k, (v, "")) }
This is a simple solution you can apply in your case
val resultMap = map1.map(kv => {
if(map2(kv._1) != None){
kv._1 -> (kv._2, map2(kv._1))
}
else{
kv
}
})
resultMap should be
Map(col_1 -> (data_1,myval_1), col_2 -> (data_2,myval_2), col_3 -> (data_3,myval_3))
Above case fails when there is no key of map1 in map2, for that case you can use match case as following
val resultMap = map1.map(kv => map2 getOrElse(kv._1, "noKey") match{
case "noKey" => kv
case x => kv._1 -> (kv._2, x)
})

How do I access "filtered" items from collection?

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?
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
}
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"))

replace string variable in Scala for solution

I have a variable which has the following data structure, I want to replace all "foo" with all "goo" for the String part. Is there any one line neat code to do that? Want to see if any smart solutions to skip to write a loop. :)
var result = List[List[(List[String], Double)]]
regards,
Lin
I am not sure if I got it right but maybe this is what you are looking for?
scala> val a: List[List[(List[String], Double)]] = List(List((List("foo asd", "asd foo"), 2.6)))
scala> a map (_ map { case (k, v) => (k map (_.replaceAll("foo", "goo")), v) })
res1: List[List[(List[String], Double)]] = List(List((List(goo asd, asd goo),2.6)))
Edit
to answer the comment let me first remove spaces and use dots
scala> a.map(_.map { case (k, v) => (k.map(_.replaceAll("foo", "goo")), v) })
and now, expand _.method(param) to x => x.method(param)
scala> a.map(b => b.map { case (k, v) => (k.map(c => c.replaceAll("foo", "goo")), v) })
You have 3 levels of nested lists, and one is inside a tuple, it won't be pretty, you need to map over each of them and extract last one from tuple.
scala> val l = List(List((List("foo","afoo"),3.4),(List("gfoo","cfoo"),5.6)))
l: List[List[(List[String], Double)]] = List(List((List(foo, afoo),3.4), (List(gfoo, cfoo),5.6)))
scala> def replaceFoo(y:List[String]) = y.map(s => s.replace("foo","goo"))
replaceFoo: (y: List[String])List[String]
scala> l.map(x => x.map(y => (replaceFoo(y._1),y._2)))
res0: List[List[(List[String], Double)]] = List(List((List(goo, agoo),3.4), (List(ggoo, cgoo),5.6)))

How to find out common tuples from list of tuples using scala?

I have two list as following-
val list1 = List(("192.168.0.1","A"),("192.168.0.2","B"),("192.168.0.3","C"))
val list2 = List(("192.168.0.104",2), ("192.168.0.119",2), ("205.251.0.185",24), ("192.168.0.1",153))
I want to match first value of both lists as shown as following:
outputList = List(("192.168.0.1","A",153))
Currently I am using following to get output -
list1.map{
ajson =>
val findHost = list2.filter(_._1.contains(ajson._1.trim))
if(findHost.nonEmpty) {
(ajson._1,ajson._2,findHost.head._2)
} else ("NA","NA",0)
}.filterNot(p => p._1.equals("NA") || p._2.equals("NA"))
Is this right approach?
I also tried
(list1 ::: list2).groupBy(_._1).map{.......}
But it gives all elements from list1.
Can anyone help me to get expected output?
You can try this:
val res = for(
(k,v) <- list1;
n <- list2.toMap.get(k)
) yield (k,v,n)
Probably most performant would be
val m1 = list1.toMap
val m2 = list2.toMap
m1.keySet.intersect(m2.keySet).map(key => (key, m1(key), m2(key)))
UPDATE
If you have more complex shapes than Tuple2 in you list for example
val list1 = List(("192.168.0.1", "A", true, 'C'), ("192.168.0.2", "B", false, 'D'), ("192.168.0.3", "C", true, 'E'))
val list2 = List(("192.168.0.104", 2, 5.7), ("192.168.0.119", 2, 13.4), ("205.251.0.185", 24, 11.2), ("192.168.0.1", 153, 34.8))
, you may need additional reshaping like
val m1 = list1.view.map { case (key, v1, v2, v3) => (key, (v1, v2, v3)) }.toMap
val m2 = list2.view.map { case (key, v1, v2) => (key, (v1, v2)) }.toMap
m1.keySet.intersect(m2.keySet).map(key => (key, m1(key), m2(key)))
Or you could use enhanced johny's version with such reshaping :
val m2 = list2.view.map { case (key, v1, v2) => (key, (v1, v2)) }.toMap
list1.collect { case (ip, x1, x2, x3) if m2 contains ip => (ip, (x1, x2, x3), m2(ip)) }
The following code should do the trick
val result = list2.flatMap {
entry =>
map.get(entry._1.trim) match {
case Some(list) =>
Some(list.map {
l =>
(l._1, l._2, entry._2)
})
case None => None
}
}.flatten
val list2Map = list2.toMap
list1.withFilter(x => list2Map.contains(x._1)).map(s => (s._1, s._2, list2Map(s._1)))

Convert all keys in a nested map to camel case in Scala

I have a map like this:
Map("first_key"->"first_value",
"second_key"->Map("second_first_key"->"second_first_value"))
How can I recursively convert all keys to like this in scala:
Map("firstKey"->"first_value",
"secondKey"->Map("secondFirstKey"->"second_first_value"))
This should do what you want:
def convert(m: Map[String, Any]): Map[String, Any] = {
m.map {
case (k, v) =>
val k2 = toCamel(k)
val v2: Any = v match {
case s: String => s
case x: Map[String, Any] => convert(x)
}
k2 -> v2
}
}
def toCamel(s: String): String = {
val split = s.split("_")
val tail = split.tail.map { x => x.head.toUpper + x.tail }
split.head + tail.mkString
}
val m = Map("first_key"->"first_value",
"second_key"->Map("second_first_key"->"second_first_value"))
convert(m)
// Map(firstKey -> first_value, secondKey -> Map(secondFirstKey -> second_first_value))