Scala:将Map映射为元组列表

18

我尝试使用Map.map将一个映射转换成元组列表,但是失败了。我进行了以下实验:

val m = Map(("a" -> 1), ("b" -> 2))
         //> m  :     scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
val r1 = m.map{ case (k,v) => v}                //> r1  : scala.collection.immutable.Iterable[Int] = List(1, 2)
def toTuple[A,B](a:A,b:B) = (a,b)               //> toTuple: [A, B](a: A, b: B)(A, B)
//val r2: List[Tuple2[_,_]] = m.map(e => (e._1,e._2))
val r3 = m.map(e => toTuple(e._1,e._2))         //> r3  : scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
val r4 = m.toSeq                                //> r4  : Seq[(String, Int)] = ArrayBuffer((a,1), (b,2))

注意当单个元素(r1)生成列表时,而元组(r3)则生成Map。甚至强制类型也不起作用(r2)。只有显式调用Seq才可以(r4)。所以我的问题是,为什么/如何Map.map“自动”创建一个新的Map而不是例如列表呢?实际上返回类型是如何确定的(Seq,List等)


6
m.toList 有什么问题?另外需要注意的是,在集合上进行映射(mapping)会返回相同类型的另一个集合,因此你无法直接返回一个映射在 Map 上的列表,除非你对其调用 .toList - Ende Neu
@Ende - 没有问题。请看下面的评论。 - user2051561
2个回答

29

Map 是一个已经包含元组的集合。

scala> "b" -> 2
res0: (String, Int) = (b,2) // Implicitly converted to a Tuple

当你映射一个Map时,你映射的是它所包含的键值对(key, value)。这样做行不通,因为你会剥离掉键,只保留值。所以现在你拥有的不再是一个Map,而是集合层次结构中更高一级的Iterable

val r1 = m.map{ case (k,v) => v} 
强制类型转换是无效的,因为Map[A,B]不是List[(A,B)]。这相当于m.map(identity)。注意,你甚至在使用元组访问器来访问e
val r2: List[Tuple2[_,_]] = m.map(e => (e._1,e._2))

val r3 = m.map(e => toTuple(e._1,e._2))

在这里,SeqList更加通用:

val r4 = m.toSeq

就像 @EndeNeu 所说的简单解决方案是只需使用 toList。当你对一个集合进行map操作时,如果可以,它应该返回原始集合类型。因此,对一个 Map 进行映射应该返回另一个 Map,除非底层结构已经使它不再是一个Map(例如完全删除键)在 r1 中。


谢谢m-z。我的问题是:在r1的情况下,Map如何知道它应该转换为List?它本来可以是其他东西吗?为什么不是数组?我假设这里有一些隐式转换。因此,我通过强制类型进行测试。关于元组,很有道理。那是Map的约定。 - user2051561
@user2051561 它不会将 r1 转换为 List -- 它返回 Iterable,因为这是与您拥有的集合类型最接近的层次结构特征。Map 扩展了 Iterable - Michael Zajac

0

为什么还要使用地图呢?对于您的用例来说,将数据结构设置为List[(String,Int)]不是更合适吗?它基本上是相同的...您甚至可以使用地图符号编写它:

val myMapAsList: List[(String, Int)] = List[(String,Int)](
    "a" -> 1,
    "b" -> 2
) // yields val myMapAsList: List[(String, Int)] = List((a,1), (b,2))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接