【问题标题】:scala map get the value by key with key case insensitivescala map 通过键获取值,不区分大小写
【发布时间】:2019-05-15 04:48:36
【问题描述】:

我有一个 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
    }
}

但是这个返回信息作为具有可序列化的产品类型,我怎样才能将信息作为 PersonInfo 类型返回? Scala中有没有一种方法可以让我按键从地图中获取价值并忽略按键的情况?

【问题讨论】:

    标签: scala hashmap


    【解决方案1】:

    有用于排序地图的比较器,可以不区分大小写地从地图中获取。示例: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 class,它实现了ProductSerializable,就像None 一样。它们的常用类型是Product with Serializable

    【讨论】:

      【解决方案2】:

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

      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】:

        您收到Product with Serializable 的原因是因为您的代码试图返回String(如果密钥正确)或Option(即None,如果找不到密钥)。这两种类型不兼容。您应该决定是否需要String(如果找不到密钥,可能是一个空字符串) Option(即Some[String]None)。

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

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

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

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

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

        【讨论】:

        • 你能解释一下这是做什么的吗?
        • 它会按照您的要求执行,但如果您的密钥中有Key 并且您要求key,它将无法正常工作。如果未找到,则询问全部大写,否则将从Some 中提取的找到值包装在Some 中。
        【解决方案4】:

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

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

        【讨论】:

        • 这是唯一真正回答标题中问题的答案。谢谢。
        猜你喜欢
        • 1970-01-01
        • 2012-02-03
        • 2020-05-15
        • 1970-01-01
        • 1970-01-01
        • 2013-10-06
        • 1970-01-01
        • 2017-10-20
        • 1970-01-01
        相关资源
        最近更新 更多