【问题标题】:Scala create immutable nested mapScala创建不可变嵌套映射
【发布时间】:2020-02-17 16:12:25
【问题描述】:

我这里有个情况

我有两个字符串

val keyMap = "anrodiApp,key1;iosApp,key2;xyz,key3"
val tentMap = "androidApp,tenant1; iosApp,tenant1; xyz,tenant2"

所以我要添加的是像这样创建一个嵌套的不可变嵌套映射

tenant1 -> (andoidiApp -> key1, iosApp -> key2),
tenant2 -> (xyz -> key3)

所以基本上想按租户分组并创建keyMap的地图

这是我尝试过的,但是使用了我想要的可变映射来完成,有没有办法使用不可变映射来创建它

case class TenantSetting() {
  val requesterKeyMapping = new mutable.HashMap[String, String]()
}

val requesterKeyMapping = keyMap.split(";")
      .map { keyValueList => keyValueList.split(',')
        .filter(_.size==2)
        .map(keyValuePair => (keyValuePair[0],keyValuePair[1]))
        .toMap
      }.flatten.toMap

    val config = new mutable.HashMap[String, TenantSetting]

    tentMap.split(";")
      .map { keyValueList => keyValueList.split(',')
        .filter(_.size==2)
        .map { keyValuePair =>
          val requester = keyValuePair[0]
          val tenant = keyValuePair[1]
          if (!config.contains(tenant)) config.put(tenant, new TenantSetting)
          config.get(tenant).get.requesterKeyMapping.put(requester, requesterKeyMapping.get(requester).get)
        }
      }

【问题讨论】:

    标签: scala nested maps immutability


    【解决方案1】:

    将字符串分解为映射的逻辑对于两者来说可以是相同的,因为它是相同的语法。

    您对第一个字符串的内容并不完全正确,因为您从拆分结果中应用到每个字符串而不是数组结果本身的过滤器。这也表明您在 keyValuePair 上使用了 [],它的类型为 String 而不是 Array[String],正如我认为的那样。您还需要一个trim 来处理第二个字符串中的空格。您可能还想修剪键和值以避免其他空白问题。

    此外,在这种情况下,映射和过滤器的组合可以使用collect 更简洁地完成,如下所示: How to convert an Array to a Tuple? 使用带有 2 个元素的模式可确保您根据需要过滤掉长度不是 2 的任何内容。 iterator 是通过只需要从第一个 split 返回的集合的一次迭代来使 map 和 collect 的组合更有效(参见下面的 cmets)。 两个字符串都变成了一个映射,它只需要正确使用groupBy,根据第二个映射的值对第一个映射进行分组,基于相同的键来获得你想要的。显然,这只有在第二个地图中始终存在相同的键时才有效。

    def toMap(str: String): Map[String, String] =
      str
        .split(";")
        .iterator
        .map(_.trim.split(','))
        .collect { case Array(key, value) => (key.trim, value.trim) }
        .toMap
    
    val keyMap = toMap("androidApp,key1;iosApp,key2;xyz,key3")
    val tentMap = toMap("androidApp,tenant1; iosApp,tenant1; xyz,tenant2")
    
    val finalMap = keyMap.groupBy { case (k, _) => tentMap(k) }
    

    打印出 finalMap 给出:

    Map(tenant2 -> Map(xyz -> key3), tenant1 -> Map(androidApp -> key1, iosApp -> key2))
    

    这是你想要的。

    【讨论】:

    • 有什么理由删除iterator
    • 因为它不是必需的。除非我错过了什么?
    • 它提高了函数的性能,因为它将在一次迭代中应用mapcollecttoMap
    • Ham,我认为您对 Iterators 是什么以及它们是如何工作的有些困惑。它们是一次性惰性集合,对它们的所有操作都将简单地附加一个要运行的计算,直到调用某些操作,例如 next()toMap。它们不应该被传递,因为很容易忘记它们是可变的并且只有一次使用,但是当你在单个集合上有一系列方法时它们非常有用(就像在这种情况下)我>。我相信您的困惑来自源代码,但是在2.11 中所有操作都进行了优化-无论如何,我将在这里停止,太离题了。
    • 哦,我得到了迭代器。我只是很少直接使用它们,也从未想过它必须如何组合操作以支持以这种方式链接方法。并且在我的记忆中将它与一些在其他地方融合严格收集操作的工作混合在一起。所以我今天学到了一些新东西。谢谢:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多