繁体   English   中英

Scala Map-使用地图功能替换键->值

[英]Scala Map - Use map function to replace key->value

我只想在key1key2的值分别为val1val2时更改它们的键和值(这两个映射都应该存在,以便进行转换)。 我可以使用以下代码来做到这一点,但是我认为这不是非常优雅或有效。

是否有更好的方法来做同样的事情,也许只使用一个应用到map的 .map函数?

码:

val map = Map(
  "key1" -> "val1",
  "key2" -> "val2",
  "otherkey1" -> "otherval1"
)

val requiredKeys = List("key1", "key2")

val interestingMap = map.filterKeys(requiredKeys.contains) // will give ("key1" -> "val1", "key2" -> "val2").

val changedIfMatched =
  if (interestingMap.get("key1").get.equalsIgnoreCase("val1") && interestingMap.get("key2").get.equalsIgnoreCase("val2"))
    Map("key1" -> "newval1", "key2" -> "newval2")
  else
    interestingMap

print(map ++ changedIfMatched) // to replace the old key->values with the new ones, if any.

还可以使++操作来更新旧的key->value映射吗?

这是一种检查两个键值对是否匹配的方法。

编辑:向Map类添加了一个mapValues方法。 该技术可用于对地图的值进行进一步检查。

val m = Map("key1" -> "val1", "key2" -> "VAL2", "otherkey1" -> "otherval1")
val oldKVs = Map("key1" -> "val1", "key2" -> "val2")
val newKVs = Map("newkey1" -> "newval1", "newkey2" -> "newval2")

implicit class MapImp[T,S](m: Map[T,S]) {
  def mapValues[R](f: S => R) = m.map { case (k,v) => (k, f(v)) }
  def subsetOf(m2: Map[T,S]) = m.toSet subsetOf m2.toSet
}

def containsKVs[T](m: Map[T,String], sub: Map[T,String]) =
  sub.mapValues(_.toLowerCase) subsetOf m.mapValues(_.toLowerCase)

val m2 = if (containsKVs(m, oldKVs)) m -- oldKVs.keys ++ newKVs else m

println(m2)
// Map(otherkey1 -> otherval1, newkey1 -> newval1, newkey2 -> newval2)

它利用了您可以将Map转换为Tuple2 SetTuple2

只需提前进行检查:

 map
   .get("k1").filter(_.equalsIgnoreCase("v1"))
   .zip(map.get("k2").filter(_.equalsIgnoreCase("v2")))
   .headOption
   .fold(map) { _ =>
      map ++ Map("key1" -> "newVal1", "key2" -> "newVal2")
   }

您可以使用以下代码:

val interestingMap = 
    if(map.getOrElse("key1", "") == "val1" && map.getOrElse("key2", "") == "val2")
      map - "key1" - "key2" + ("key1New" -> "val1New") + ("key2New" -> "val2New")
    else map

检查部分( if声明)可以进行调整以满足您的特定需求。

如果映射中不存在任何这些键/值对,则将返回原始映射,否则,您将获得一个新的映射,并在请求的密钥处进行两次更新。

关于效率,只要只更新两个密钥,我认为使用+直接添加元素和使用++运算符覆盖密钥批发之间并没有真正的性能差异。 如果您的地图很大,从长远来看,也许使用可变地图被证明是一个更好的选择。

回答修改后的问题

val map = Map(
  "key1" -> "val1",
  "key2" -> "val2",
  "otherkey1" -> "otherval1"
)

val requiredVals = List("key1"->"val1", "key2"->"val2")
val newVals = List("newval1", "newval2")

val result =
  if (requiredVals.forall{ case (k, v) => map.get(k).exists(_.equalsIgnoreCase(v)) }) {
    map ++ requiredVals.map(_._1).zip(newVals)
  } else {
    map
  }

该解决方案使用forall通过依次测试每一对来检查是否在映射中找到了requiredKeys中的所有键/值对。

对于每个键/值对(k, v)它执行get使用该密钥来检索当前值作为在地图上Option[String] 如果找不到密钥,则为None如果找到密钥,则为Some(s)

然后,该代码调用existsOption[String] 如果值是None (找不到键),则此方法将返回false ,否则它将返回传递给它的测试结果。 测试是_.equalsIgnoreCase(v) ,它对Option的内容( _ )和requireKeys列表( v )中的值进行不区分大小写的比较。

如果此测试失败,则返回map的原始值。

如果此测试成功,则返回映射的修改版本。 表达requiredVals.map(_._1)返回从钥匙requireVals列表,以及zip(newVals)的新值与原来的密钥相关联。 生成的值列表将使用++添加到地图中, ++会将现有值替换为新值。

原始答案

val map = Map(
  "key1" -> "val1",
  "key2" -> "val2",
  "otherkey1" -> "otherval1"
)

val requiredVals = Map("key1"->"val1", "key2"->"val2")
val newVals = Map("newkey1" -> "newval1", "newkey2" -> "newval2")

val result =
  if (requiredVals.forall{ case (k, v) => map.get(k).exists(_.equalsIgnoreCase(v)) }) {
    map -- requiredVals.keys ++ newVals
  } else {
    map
  }

请注意,这用新密钥替换了旧密钥,新密钥似乎就是所描述的。 如果要保留原始键和值,只需删除“-requiredVals.keys”,它将添加新键而不删除旧键。

我认为这将是解决该问题的最通用且可恢复的解决方案。

object Solution1 extends App {

  val map = Map(
    "key1" -> "val1",
    "key2" -> "val2",
    "otherkey1" -> "otherval1"
  )

  implicit class MapUpdate[T](map: Map[T, T]) {
    def updateMapForGivenKeyValues: (Iterable[(T, T)], Iterable[(T, T)]) => Map[T, T] =
      (fromKV: Iterable[(T, T)], toKV: Iterable[(T, T)]) => {

        val isKeyValueExist: Boolean = fromKV.toIterator.forall {
          (oldKV: (T, T)) =>
            map.toIterator.contains(oldKV)
        }

        if (isKeyValueExist) map -- fromKV.map(_._1) ++ toKV else map
      }
  }


  val updatedMap = map.updateMapForGivenKeyValues(List("key1" -> "val1", "key2" -> "val2"),
    List("newKey1" -> "newVal1", "newVal2" -> "newKey2"))

  println(updatedMap)

}

因此, updateMapForGivenKeyValues方法采用旧键值和新键值元组的列表。 如果该方法的第一个参数中提到的所有键值对都存在于映射中,则只有我们将使用该方法的第二个参数中提到的新键值对来更新映射。 由于该方法是通用的,因此可以在任何数据类型(如String,Int,某些case类等)上使用。

我们可以轻松地将该方法用于不同类型的地图,而无需更改任何代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM