2010-05-27 40 views
26

Tôi có một Seq đối tượng chứa của một lớp trông như thế này:Làm thế nào để chuyển đổi một Seq [A] thành một bản đồ [Int, A] bằng cách sử dụng giá trị của A làm khóa trong bản đồ?

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

Bây giờ tôi muốn chuyển đổi này Seq đến một Map, sử dụng giá trị key của từng đối tượng như chìa khóa, và các đối tượng chính nó như là giá trị. Vì vậy:

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

Làm cách nào tôi có thể thực hiện điều này một cách hiệu quả và thanh lịch trong Scala 2.8?

+0

Out of curio có ai không biết tại sao điều này không có trong thư viện sưu tập Scala? – tksfz

Trả lời

24

Bản đồ trên Seq và tạo một chuỗi các bộ dữ liệu. Sau đó, sử dụng các bộ dữ liệu đó để tạo một Map. Làm việc trong tất cả các phiên bản của Scala.

val map = Map(seq map { a => a.key -> a }: _*) 
+2

Sử dụng 'breakOut' như Seth Tisue hiển thị trong câu trả lời khác có thể làm cho nó hiệu quả hơn bằng cách tránh tạo ra một chuỗi tạm thời các bộ dữ liệu. – Jesper

44

Kể từ 2,8 Scala được ghé thăm .toMap, vì vậy:

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

hoặc nếu bạn gung ho về việc tránh xây dựng một chuỗi trung gian của các bộ:

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

+0

Cảm ơn. Tôi đã nhìn thấy điều 'breakOut' trước đây nhưng tôi vẫn chưa biết nó là gì. Đã đến lúc học lại điều gì đó mới mẻ. – Jesper

+3

Tìm thấy một giải thích tốt về 'breakOut' ở đây: http: // stackoverflow.com/questions/1715681/scala-2-8-breakout/1716558 # 1716558 – Jesper

+0

Tại sao bản đồ val = Seq (1,2,3) .map (a => a -> a) (collection.breakOut) là thực sự của loại Vector? bản đồ: scala.collection.immutable.IndexedSeq [(Int, Int)] = Vector ((1,1), (2,2), (3,3)) – simou

5

Thêm 2,8 biến thể, để có biện pháp tốt, cũng hiệu quả:

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))) 

Lưu ý rằng nếu bạn có khóa trùng lặp, bạn sẽ loại bỏ một số khóa trong khi tạo Bản đồ! Bạn có thể sử dụng groupBy để tạo ra một bản đồ, nơi mỗi giá trị là một chuỗi:

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)))) 
1

Như scala biết để chuyển đổi một tuple từ hai đến một bản đồ, trước tiên bạn muốn chuyển đổi seq của bạn đến một tuple và sau đó để lập bản đồ như vậy (không quan trọng nếu nó là int, trong chuỗi trường hợp của chúng tôi, string):

thuật toán nói chung là thế này:

  1. Đối với mỗi mục trong Seq
  2. món hàng -> tuple (key, giá trị)
  3. Đối với mỗi tuple (key, value)
  4. tổng hợp vào Map (key, giá trị)

Hoặc để tổng hợp:

Bước 1: Seq -> tuple của hai

bước 2: tuple hai -> Bản đồ

Ví dụ:

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) 
Các vấn đề liên quan