Scala Map-如果不存在密钥,尝试其他密钥的最佳方法是什么

时间:2019-09-19 22:24:12

标签: scala scala-collections

给出Scala中的Map,我想尝试第一个键,如果找不到,请尝试其他键,如果再次找不到,则返回None。预期效果如下:

val scores: Map[String, Int] = Map("Alice" -> 10, "Bob" -> 3)
val singleGet: Option[Int] = scores.get("NotAKey")
println(singleGet) // None
val doubleGet = scores.getOrElse("NotAKey", scores.get("NotAKeyAgain")) // works ok if no type
println(doubleGet) // None

但是,如果我为doubleGet输入类型,则会出错:

val doubleGet: Option[Int] = scores.getOrElse("NotAKey", scores.get("NotAKeyAgain")) // ERROR

“类型Any的表达式与预期的类型Option [Int]不符”

那么最好的方法是什么?

1 个答案:

答案 0 :(得分:2)

您对要执行的操作有很好的直觉,即:
“测试一个密钥,如果不存在,请检查第二个密钥。”

此外,您对返回类型是正确的,因为您没有提供任何默认值,并且不能保证其中任何一个键都应该存在。
但是,您的问题是scores.getOrElse("NotAKey", scores.get("NotAKeyAgain"))将返回任何
为什么?因为getOrElse返回两个替代方案的 LUB (最小上限)。在这种情况下,默认值为Option[Int],但成功检索第一个键的类型为Int

您真正需要的是一种组合两个 Options 的方法,如果第一个不存在,则使用第二个。这正是orElse所做的。

您可以在地图上创建一些扩展方法,以使使用更加容易。

implicit class MapOps[K, V](private val map: Map[K, V]) extends AnyVal {
  def doubleGet(key1: K, key2: K): Option[V] =
    map.get(key1) orElse map.get(key2)

  def doubleGetOrElse[V1 >: V](key1: K, key2: K)(default: => V1): V1 =
    (map.get(key1) orElse map.get(key2)).getOrElse(default)

  def multiGet(keys: K*): Option[V] =
    keys.iterator.map(key => map.get(key)).foldLeft(Option.empty[V])(_ orElse _)

  def multiGetOrElse[V1 >: V](keys: K*)(default: => V1): V1 =
    keys.iterator.map(key => map.get(key)).foldLeft(Option.empty[V])(_ orElse _).getOrElse(default)
}

val scores: Map[String, Int] = Map("Alice" -> 10, "Bob" -> 3)
scores.doubleGet("A", "B") // res: Option[Int] = None
scores.multiGet("A", "Alice", "B") // res: Option[Int] = Some(10)