2010-05-27 14 views
26

Mam Seq zawierające obiekty klasy, która wygląda tak:Jak przekonwertować Seq [A] na mapę [Int, A], używając wartości A jako klucza na mapie?

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

Teraz chcę przekonwertować ten Seq do Map, stosując wartość key każdego obiektu jako klucz, a sam obiekt jako wartość. A więc:

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

Jak mogę to zrobić skutecznie i elegancko w Scali 2.8?

+0

Spośród ciekawostka Czy ktoś może wiedzieć, dlaczego nie ma go w bibliotece kolekcji Scala? – tksfz

Odpowiedz

24

Wyświetl mapę nad swoim numerem Seq i wygeneruj sekwencję krotek. Następnie użyj tych krotek, aby utworzyć Map. Działa we wszystkich wersjach Scali.

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

Użycie 'breakOut', jak pokazuje Seth Tisue w innej odpowiedzi, może uczynić ją bardziej wydajną, unikając tworzenia tymczasowej sekwencji krotek. – Jesper

44

Od 2,8 Scala miał .toMap, więc:

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

lub jeśli jesteś gung ho o unikaniu budowy pośrednią sekwencję krotek:

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

+0

Dzięki. Widziałem już coś "breakOut", ale jeszcze nie wiem, co to jest. Czas ponownie nauczyć się czegoś nowego. – Jesper

+3

Znaleźliśmy dobre wyjaśnienie 'breakOut' tutaj: http: // stackoverflow.com/questions/1715681/scala-2-8-breakout/1716558 # 1716558 – Jesper

+0

Dlaczego jest to mapa val = Seq (1,2,3) .map (a => a -> a) (collection.breakOut) to faktycznie typu Vector? mapa: scala.collection.immutable.IndexedSeq [(Int, Int)] = Vector ((1,1), (2,2), (3,3)) – simou

5

Jeszcze jedna wersja 2.8, dla dobrego pomiaru, również wydajna:

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

Pamiętaj, że jeśli masz zduplikowane klucze, niektóre z nich odrzucisz podczas tworzenia mapy! Można użyć groupBy stworzyć mapę, gdzie każda wartość jest sekwencją:

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

Jak scala wie przekonwertować krotki dwóch do mapy, byś najpierw chcą zamienić nast do krotki, a następnie do mapy tak (nie ma znaczenia czy jest to int, w naszym przypadku łańcucha, łańcuch):

ogólny algorytm jest następujący:

  1. Dla każdej pozycji w SEQ
  2. Item -> Tuple (klucz, wartość)
  3. Dla każdej krotki (klucz, wartość)
  4. zbiorczej mapie (klucz, wartość)

Albo Podsumowując:

Krok 1: sekwencyjny -> Tuple dwóch

Krok 2: krotka dwa -> Mapa

Przykład:

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) 
Powiązane problemy