如何根据模式匹配将一个映射中的值替换为另一个映射中的值?

时间:2019-06-29 01:33:29

标签: algorithm scala functional-programming maps match

我有一个具有几个键值对的映射,并且我想要一种遍历这些对并尝试将键与另一个映射的值匹配的方法。如果存在匹配项,则值将相互替换。换句话说,如果存在匹配,则将第二张地图的匹配值替换为第一张地图的值。如果没有匹配项,则不包括在结果中。

我尝试使用scala .map函数来弄清楚逻辑,但是我对scala还是陌生的,无法完全弄清楚。

例如,我有以下两个scala Map [String,String]:

val lookupMap = Map("aaa" -> "apple", "bbb" -> "orange", "ccc" -> "banana")

val entriesMap = Map("foo" -> "ccc", "bar"-> "aaa", "baz" -> "zzz") 

我想通过某种方式获得以下结果:

val result = Map("foo" -> "banana", "bar" -> "apple")

注意:不包含“ baz”,因为它与查找映射中的任何内容都不匹配。

2 个答案:

答案 0 :(得分:4)

for的理解可以解决这一问题。

val result = for {
               (k,ev) <- entriesMap
               lv     <- lookupMap.get(ev)
             } yield (k,lv)
//result: Map[String,String] = Map(foo -> banana, bar -> apple)

答案 1 :(得分:3)

让我们以更简单的步骤解决您的问题。

  1. 过滤掉entriesMap上不存在其值的所有对作为lookupMap中的键。
  2. 映射其余对以更改与原始值关联的lookupMap上的值。

因此,您可以编写以下内容:

val result =
  entriesMap
    .filter { case (_, value) => lookupMap.contains(key = value) }
    .map { case (key, value) => key -> lookupMap(value) }

但是,每次您要先filter然后再map时,都可以始终使用collect (这将完成相同的工作,但仅一次迭代)
因此,您可以这样编写:

val result = entriesMap.collect {
  case (key, value) if lookupMap.contains(key = value) => key -> lookupMap(value)
}

现在,上面代码中的一个“问题” 是,它在 Map 上使用了 unsafe apply,如果它们的键不存在,将抛出异常。 通常,应该使用get方法,该方法将返回包装在 Option 上的值,如果键不存在,则该值将为None

在这种情况下,访问并非不安全,因为我们正在检查密钥是否存在。
无论如何,人们可以将程序重新考虑为:

  1. 尝试通过获取entriesMap上的关联值来映射lookupMap的值。
  2. 过滤掉其值现在为None的货币对,并展开Somes

代码如下:

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.

最后,可以直接使用来理解,而不是直接使用高阶函数。
因此,这段代码(与jwvh的答案几乎相同)

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.