我有一个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 中以优雅的方式高效地做到这一点?
我有一个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 中以优雅的方式高效地做到这一点?
由于 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
映射你的Seq
并产生一个元组序列。然后使用这些元组创建一个Map
. 适用于所有版本的 Scala。
val map = Map(seq map { a => a.key -> a }: _*)
另一个 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))))
正如 scala 知道将两个元组转换为映射一样,您首先需要将您的 seq 转换为元组,然后再映射(不管它是否是 int,在我们的例子中是字符串,字符串):
一般算法是这样的:
或者总结一下:
第 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)