I have a method as follows:
protected def extract(implicit params:Params) =
Map(
"address" -> params.address,
"city" -> params.address,
"region" -> params.region,
)collect {
case (k, v) if v.isDefined => k -> v.get
}
I want to substitute value of city such that :
"city" -> if(params.city.contains("York")) "NewYork" else params.city,
How can I achieve this in scala?
You could put it in line
def extract(implicit params:Params) =
Map(
"address" -> params.address,
"city" -> (if(params.city.contains("York")) Some("NewYork") else params.city),
"region" -> params.region
) collect {
case (k, v) if v.isDefined => k -> v.get
}
Im sure there are lots of other way to do it. Not sure what your really after.
Stephens approach of just creating the map with the correct value is probably best. If you've got a general map, of what appears to be String to Option[String], and want to substitute the city key if the value contains York, then this will work as well.
myMap.collect {
case ("city", Some(city)) if(city.contains("York")) => "NewYork"
case (k, v) if v.isDefined => k -> v.get
}
Small correction to Bruce answer
myMap.collect {
case ("city", Some(city)) if(city.contains("York")) => "NewYork"
case (k, v) if v.isDefined => k -> v.get
}
Would not result in a Map, but an Iterable
myMap.collect {
case ("city", Some(city)) if(city.contains("York")) => "city" -> "NewYork"
case (k, Some(v)) => k -> v
}
Would be better
Related
I have a Map which has a key containing another Map.
i.e -
val myDetailsMap = Map("name" -> "abc",
"class" -> "10",
"section" -> "A",
"marksPerSubjectId" -> Map(101 -> "Physics= '70' AND Chemistry='80'",
102 -> "History= '60' AND Civics = '67'"),
"status" -> "pass")
Now, I want to iterate through the marksPerSubjectId key containing another MAP using foreach. How should I proceed ?
On Databricks -
What about using pattern matching?
in Scala 2.13:
myDetailsMap.foreachEntry{ (k, v) =>
v match {
case map: Map[_, _] => map.foreachEntry{ (k, v) => println(v)}
case other => println(other)
}
}
in Scala 2.11:
myDetailsMap.foreach{ case (k, v) =>
v match {
case map: Map[_, _] => map.foreach{ case (k, v) => println(v)}
case other => println(other)
}
}
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)
})
My program receives a scala map, the requirements is to validate this map (key-value pairs). Ex: validate a key value, change its value to an acceptable format etc. In a rare case, we update the key as well before passing the map to the down layer. Its not always required to update this map , but only when we detect that there are any unsupported keys or values. However, we have to check all key/value pairs. I'm doing some thing like this:
private def updateMap ( parameters: Map[String, String]): Map[String, String] = {
parameters.map{
case(k,v) => k match { case "checkPool" =>
(k, (if (k.contains("checkPool"))
v match {
case "1" => "true"
case _ => "false"
}
else v))
case "Newheader" => (k.replace("Newheader","header"),v)
case _ =>(k,v)
}
case _ => ("","")
}
}
Like this the code increases for doing the validation and converting the keys/values to supported ones. Is there a cleaner way of doing this validation in Scala for a map?
Thanks
It will be clearer if you put all your patterns above one another:
parameters.map{
case (k#"checkPool", "1") => k -> "true"
case (k#"checkPool", _") => k -> "false"
case ("Newheader", v) => "header" -> v
// put here all your other cases
case (k, v) => k -> v //last possible case, if nothing other matches
}
For clarity, you can also put different validators in partial functions:
type Validator = PartialFunction[(String, String), (String, String)
val checkPool: Validator = {
case (k#"checkPool", "1") => k -> "true"
case (k#"checkPool", _") => k -> "false"
}
val headers: Validator = {
case ("Newheader", v) => "header" -> v
}
And then put all your validators one after the other in your map:
parameters.map(
checkPool orElse
headers orElse
... orElse
PartialFunction(identity[(String, String)]) //this is the same as case (k, v) => k -> v
)
simple if else condition matching seems to be the best choice.
def updateMap(parameters: Map[String, String]): Map[String, String] = {
parameters.map(kv => {
var key = kv._1
var value = kv._2
if(key.contains("checkPool")){
value = if(value.equals("1")) "true" else "false"
}
else if(key.contains("Newheader")){
key = key.replace("Newheader", "header")
}
(key, value)
})
}
You can add more else if conditions
I have the following map with target node "E":
val map = Map("A" -> "B", "A" -> "C", "C" -> "D", "C" -> "E")
It describe a directed node graph, which looks like:
A
/ \
B C
/ \
D E
I need to enter the graph at any point and generate a route to the target node.
Example 1: Enter at A -> Route: A->C->E
Example 2: Enter at D -> Route: D->C->E
Example 3: Enter at B -> Route: B->A->C->E
Does anyone know of a compact algo which could do this as this must have been attempted before.
Look forward to hearing from you.
Cheers,
Jez
So, here is it:
val map = List("A" -> "B", "A" -> "C", "C" -> "D", "C" -> "E")
def pathOf(tree: Iterable[(String,String)],from: String,to: String, path: List[String] = Nil): List[String] = {
if(from == to) return to::path
tree.filterNot{ case(a,b) => path.contains(a)||path.contains(b) }
.collect{
case (a,b) if a == to => b
case (a,b) if b == to => a
}.map{ x => pathOf(tree,from,x,to::path) }
.find{ _.nonEmpty }
.getOrElse(Nil)
}
Use case:
scala> pathOf(map,"B","E").mkString("->")
res1: String = B->A->C->E
scala> pathOf(map,"C","E").mkString("->")
res2: String = C->E
As relatively new to Scala, I take this problem as a good exercise for myself and would like to share my solution with all of you. Any comments are welcomed!
BTW, the solution given by #Eastsun is a depth-first search which "memorizes" visited nodes in each path, while mine is a breadth-first search where memorization is not required (though you can definitely add this feature to improve efficiency). For trees they yield the same answer but for general graphs they can differ.
The neighbors of each node can also be cached for optimization.
val graph = Vector(("A","B"), ("A","C"), ("C","D"), ("C","E"))
def adjacent(a: String) = {
graph flatMap {
case (`a`, x) => Some(x)
case (x, `a`) => Some(x)
case _ => None
}
}
def go(from: String, to: String) {
def expand(paths: Vector[Vector[String]]) {
paths.find(_.last==to) match {
case Some(x) => println(x); return
case None => expand(paths flatMap { e =>
adjacent(e.last) map (e :+ _)
})
}
}
expand(Vector(Vector(from)))
}
// tests
go("A","E") // Vector(A, C, E)
go("B","E") // Vector(B, A, C, E)
go("D","E") // Vector(D, C, E)
Version with memorization: change
adjacent(e.last) map (e :+ _)
to
adjacent(e.last) filterNot (x => paths.flatten contains x) map (e :+ _)
or put this functionality in the adjacent function.
I got the following list of pairs:
List(("US","New York"),("England","London"),("US","Los Angeles"),("England","Manchester"),("US","Washington"))
I need to generate a Map[Country, List[Cities]]:
Map("US" -> List("New York", "Los Angeles", "Washington"), "England" -> List("London", "Manchester"))
The problem that if I use toMap() directly the values with same keys are removed.
The story so far:
list.groupBy(el => el).map(el => el._1 -> ?)
using groupBy:
list.groupBy(_._1).mapValues(_.map(_._2))
using fold:
list.foldLeft(Map.empty[String, List[String]]) { case (m, (k, v)) =>
m.updated(k, v :: m.getOrElse(k, List()))
}