Reputation: 191
I have a map that has a few key value pairs, and I would like a way to go through those pairs and attempt to match the keys with the value of another map. If there's a match the values are substituted for each other. In other words, if there's a match value of the second map is substituted for the value of the first map. If there is no match, it is not included in the result.
I've tried figuring out the logic use the scala .map function but I'm new to scala and can't quite figure it out.
For example, I have the following two scala Map[String, String]:
val lookupMap = Map("aaa" -> "apple", "bbb" -> "orange", "ccc" -> "banana")
val entriesMap = Map("foo" -> "ccc", "bar"-> "aaa", "baz" -> "zzz")
I would like some way to get the following result:
val result = Map("foo" -> "banana", "bar" -> "apple")
Note: "baz" was not included because it did not match to anything in the lookup Map.
Upvotes: 2
Views: 1725
Reputation: 22840
Lets break down your problem in simpler steps.
entriesMap
whose value does not exists as a key in the lookupMap
.lookupMap
associated with the original value.Thus, you can write the following:
val result =
entriesMap
.filter { case (_, value) => lookupMap.contains(key = value) }
.map { case (key, value) => key -> lookupMap(value) }
However, every time that you want to filter
and then map
, you can always use collect
(which will do the same job, but in just one iteration).
Thus, you can write this:
val result = entriesMap.collect {
case (key, value) if lookupMap.contains(key = value) => key -> lookupMap(value)
}
Now, one "problem" with the above code is that it uses the unsafe apply
over a Map, which will throw an exception if they key does not exists.
Usually, one should use the get
method, which would return the value wrapped on an Option, which will be a None
if the key did not existed.
In this case, the access is not unsafe, because we are checking if the key exists before.
Anyways, one could rethink the program as:
entriesMap
by attempting to get their associated value on the lookupMap
.None
and unwrapping the Somes
.The code will be as follows:
val result =
entriesMap
.view // Only if you are in 2.13
.mapValues(value => lookupMap.get(key = value))
.collect { case (key, Some(value)) => key -> value }
.toMap // This is necessary because mapValues returns a view, which is a lazy collection.
// Other option would have been to use just map instead of mapValues.
Finally, instead of using higher order functions directly, one could use for comprehension.
Thus, this code (almost the same as the one from jwvh's answer):
val result =
for {
(key, value) <- entriesMap // For each key-value pair in entriesMap...
newValue <- lookupMap.get(key = value) // And for each newValue associated with each original value...
} yield key -> newValue // Yield the key-newValue pair.
Upvotes: 3
Reputation: 51271
A for
comprehension can clean that up.
val result = for {
(k,ev) <- entriesMap
lv <- lookupMap.get(ev)
} yield (k,lv)
//result: Map[String,String] = Map(foo -> banana, bar -> apple)
Upvotes: 5