45

我有一个Seq类的包含对象,如下所示:

class A (val key: Int, ...)

现在我想将它转换Seq为 a Map,使用key每个对象的值作为键,对象本身作为值。所以:

val seq: Seq[A] = ...
val map: Map[Int, A] = ... // How to convert seq to map?

我怎样才能在 Scala 2.8 中以优雅的方式高效地做到这一点?

4

4 回答 4

87

由于 2.8 Scala 已经有了.toMap,所以:

val map = seq.map(a => a.key -> a).toMap

或者,如果您非常想避免构建元组的中间序列,那么在 Scala 2.8 到 2.12 中:

val map: Map[Int, A] = seq.map(a => a.key -> a)(collection.breakOut)

或在 Scala 2.13 和 3 中(没有breakOut,但确实有可靠的.view):

val map = seq.view.map(a => a.key -> a).toMap
于 2010-05-27T23:05:39.443 回答
45

映射你的Seq并产生一个元组序列。然后使用这些元组创建一个Map. 适用于所有版本的 Scala。

val map = Map(seq map { a => a.key -> a }: _*)
于 2010-05-27T22:08:38.960 回答
7

另一个 2.8 变体,为了更好的衡量,也很有效:

scala> case class A(key: Int, x: Int)
defined class A

scala> val l = List(A(1, 2), A(1, 3), A(2, 1))
l: List[A] = List(A(1,2), A(1,3), A(2,1))

scala> val m: Map[Int, A] = (l, l).zipped.map(_.key -> _)(collection.breakOut)
m: Map[Int,A] = Map((1,A(1,3)), (2,A(2,1)))

请注意,如果您有重复的键,您将在 Map 创建期间丢弃其中的一些!您可以使用groupBy创建一个映射,其中每个值都是一个序列:

scala> l.groupBy(_.key)
res1: scala.collection.Map[Int,List[A]] = Map((1,List(A(1,2), A(1,3))), (2,List(A(2,1))))
于 2010-05-28T04:51:13.667 回答
2

正如 scala 知道将两个元组转换为映射一样,您首先需要将您的 seq 转换为元组,然后再映射(不管它是否是 int,在我们的例子中是字符串,字符串):

一般算法是这样的:

  1. 对于 Seq 中的每个项目
  2. 项目 --> 元组(键,值)
  3. 对于每个元组(键,值)
  4. 聚合到 Map(key,value)

或者总结一下:

第 1 步:Seq --> 两个元组

第 2 步:二元组 --> 映射

例子:

case class MyData(key: String, value: String) // One item in seq to be converted to a map entry.

// Our sequence, simply a seq of MyData
val myDataSeq = Seq(MyData("key1", "value1"), MyData("key2", "value2"), MyData("key3", "value3")) // List((key1,value1), (key2,value2), (key3,value3))

// Step 1: Convert seq to tuple
val myDataSeqAsTuple = myDataSeq.map(myData => (myData.key, myData.value)) // List((key1,value1), (key2,value2), (key3,value3))

// Step 2: Convert tuple of two to map.
val myDataFromTupleToMap = myDataSeqAsTuple.toMap // Map(key1 -> value1, key2 -> value2, key3 -> value3)
于 2018-02-07T12:09:39.483 回答