【发布时间】:2018-04-11 08:40:25
【问题描述】:
我需要转换以下地图:
Map(1 -> Seq("A", "E"), 2 -> Seq("D", "G"))
到:
Map("a" -> 1, "d" -> 2, "e" -> 1, "g" -> 2)
我该如何解决?
谢谢!!!
【问题讨论】:
标签: scala collections
我需要转换以下地图:
Map(1 -> Seq("A", "E"), 2 -> Seq("D", "G"))
到:
Map("a" -> 1, "d" -> 2, "e" -> 1, "g" -> 2)
我该如何解决?
谢谢!!!
【问题讨论】:
标签: scala collections
假设m 是您的输入映射,
for ((v, ks) <- m; k <- ks) yield (k.toLowerCase, v)
产生:
Map(a -> 1, e -> 1, d -> 2, g -> 2)
这实际上是配方的 1:1 翻译:“对于原始映射中的每一对整数值 v 和字母列表 ks,从 ks 中获取每个字母 k 并添加将(k, v) 与新地图配对”。
【讨论】:
flatMap 和 map 的突然流行感到有些惊讶:我们已经有了简短的 for-syntax ,为什么不使用它?就好像 Python 用户会突然开始用__iter__-方法重写他们所有的列表理解......我很困惑。 O_o?
for/yield 在许多(如果不是大多数)情况下更容易理解。也许flatMap 和map 方法在几乎所有类型的Scala 集合/容器中的突出地位可能有助于以某种方式宣传自己。或者,也许人们只是不想成为slapped 因为不使用它。
flatMap 替换嵌套的match { case Some(...) => { ... match case Some(...) => ... } ... case None => }-thingies 的塔,然后最终用for-comprehensions,因为它们没有t 为每个新的绑定变量引入一级缩进......这对for-syntax imho 的影响较小。我不知道,for 在这种特殊情况下似乎更合适。
for 而不是flatMap,事实上,我投票率最高的问题之一正是关于a case where for-comprehension fails badly, but flatMap works nicely。但在这种特殊情况下,我看不出有任何理由不使用for-yield。
使用flatMap 并使用映射将内部列表转换为所需的形式。
警告:序列不能有重复。
scala> val map = Map(1 -> Seq("A", "E"), 2 -> Seq("D", "G"))
map: scala.collection.immutable.Map[Int,Seq[String]] = Map(1 -> List(A, E), 2 -> List(D, G))
scala> map.flatMap { case (k, v) => v.map(_.toLowerCase -> k) }
res0: scala.collection.immutable.Map[String,Int] = Map(a -> 1, e -> 1, d -> 2, g -> 2)
【讨论】:
toMap 是多余的。如果回调中的返回值是元组的可迭代,则在 Map 上调用的 flatMap 将是 Map。
for-comprehension 语法,如果已经有map,是否真的有必要调用变量map和flatMap 在表达式中?无论我在哪里看到一个孤立的map,我都会自动开始搜索集合c,在该集合上应该调用方法c.map...
您可以执行以下操作
val m = Map(1 -> Seq("A", "E"), 2 -> Seq("D", "G"))
println(m.flatMap(x => x._2.map(y => (y.toLowerCase, x._1))))
你会得到
Map(a -> 1, e -> 1, d -> 2, g -> 2)
【讨论】:
map.flatMap(map => map._2.map(flatMap => (flatMap.toLowerCase, map._1)))呢? ;)
map-flatMap-方法调用本身已经有些密集(这就是发明for-syntax的原因),并添加额外的变量名称也称为map 似乎并没有使它更容易阅读。
Map“地图”称为“地图”的提案中都指出了这一点。感谢您更新答案,我发现它已经好多了;)
另一个答案是正确的,但对于刚接触 scala 的人来说,他们可能很难理解。 下面简单易懂
val z = Map(1 -> Seq("A", "E"), 2 -> Seq("D", "G"))
z.map{case (i,l) => l.map(s=> (s.toLowerCase->i))}.flatten.toMap
【讨论】:
flatten 与flatMap(identity) 相同,您可以将其简化为更简单的z.flatMap{ case (i, l) => l.map(s => (s.toLowerCase -> i)) }.toMap,因为现在您可以删除toMap,所以您最终会得到@ pamu 的解决方案,如果您现在将flatMap { case (i, l) => ...} 进一步简化为简洁的for-comprehension,您将获得for ((i,l) <- z; s <- l) yield (s.toLowerCase -> i)。老实说,我不知道为什么每个人都认为将 for-comprehensions 扩展到低级 flatMap-implementation 细节会使任何事情变得更简单......
for ((number, sequence) <- m; letter <- sequence) yield (letter, number)。在这种情况下,flatMap 是一个无关紧要的实现细节。
我们也可以使用collect来实现这个
scala> val map =Map(1 -> Seq("A", "E"), 2 -> Seq("D", "G"))
map: scala.collection.immutable.Map[Int,Seq[String]] = Map(1 -> List(A, E), 2 -> List(D, G))
scala> map.collect{case (k,v) => v.map(_.toLowerCase -> k)}.flatten.toMap
//res2: scala.collection.immutable.Map[String,Int] = Map(a -> 1, e -> 1, d -> 2, g -> 2)
【讨论】:
collect等同于使用map,而collect { ... }.flatten.toMap在这种情况下等同于仅使用flatMap。