Scala映射通过不区分大小写的键来通过键获取值

时间:2019-05-15 04:48:36

标签: scala hashmap

我有一个Map [String,Info]的映射,它包含可以是大写或小写的键,如下所示:

person1: PersonInfo1
person2: PersonInfo2
PERSON1: PersonInfo1

我想获取键“ person1”的值,如果什么都找不到,我将尝试使用“ PERSON1”的键,我尝试了以下代码:

val info = map.get(key) match {
  case Some(personInfo) => personInfo
  case None =>
    map.get(key.toUpperCase()) match {
      case Some(personInfo) => personInfo
      case None             => None
    }
}

但是此返回信息作为具有Seri​​alizable的产品类型,我如何将信息作为PersonInfo类型返回? Scala中是否有一种方法可以让我通过键从地图中获取价值,而忽略键的情况?

4 个答案:

答案 0 :(得分:4)

有一些用于排序图的比较器,这些比较器允许不敏感地从图例中获取。示例:https://scastie.scala-lang.org/PfHTh16CROag7PNrknx1sQ

val map = scala.collection.immutable.SortedMap("key1" -> 45, "Key2" -> 43, "KEY3" -> 42)(scala.math.Ordering.comparatorToOrdering(String.CASE_INSENSITIVE_ORDER))
map.get("key1") // Some(45)
map.get("key2") // Some(43)
map.get("key3") // Some(42)
map.get("key4") // None

如果在所有情况下都返回“选项”,则可以解决您的实际问题,例如:

      val info = map.get(key) match {
        case somePi@Some(personInfo) => somePi
        case None => map.get(key.toUpperCase()) match {
          case Some(personInfo) => Some(personInfo)
          case None => None
        }
      }

请注意somePi@ => somePi部分用于引用表达式或Some(personInfo)

大概值得解释为什么,您收到此错误消息。我假设personInfo是实现case classProduct的{​​{1}},就像Serializable一样。它们的常见类型是None

答案 1 :(得分:4)

得到Product with Serializable的原因是因为您的代码试图返回String(如果键是好的)或Option(即None找不到密钥)。这两种类型不兼容。您应该决定是否要使用String(如果找不到密钥,则可以为空字符串) Option(即Some[String]None)。 / p>

看看这是否适合您。它返回一个Option[String]

map.get(key).fold(pm.get(key.toUpperCase))(Some(_))

第一个get()返回一个Optionfold()()会解开Option并尝试使用大写get()值的第二个key,或者,如果第一个get返回一个值,则该值为重新包装在Option中,以使类型匹配。

另一方面,如果您想返回一个String,则可以这样做。

map.getOrElse(key, pm.getOrElse(key.toUpperCase, ""))

答案 2 :(得分:4)

您可以使用orElse链接获取。我将为此创建一个扩展方法:

implicit class CaseInsensitiveGetMap[V] (m: Map[String,V]) {
   def iget (key: String): Option[V] = m.get(key)
      .orElse(m.get(key.toUpperCase())) //you can add more orElse in chain
}

然后您可以像使用它一样

map.iget("person2")

答案 3 :(得分:0)

您可以使用 find 而不是 get,但您在执行此操作时可能需要考虑性能。

map.find(k => k._1.equalsIgnoreCase(key)) match {
  case Some =>
  case None =>
}