web-dev-qa-db-fra.com

Comment convertir un Seq [A] en une carte [Int, A] en utilisant une valeur de A comme clé dans la carte?

J'ai un Seq contenant des objets d'une classe qui ressemble à ceci:

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

Maintenant, je veux convertir ce Seq en Map, en utilisant la valeur key de chaque objet comme clé et l'objet lui-même comme valeur. Alors:

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

Comment puis-je le faire de manière efficace et élégante dans Scala 2.8?

40
Jesper

Mappez sur votre Seq et produisez une séquence de tuples. Utilisez ensuite ces tuples pour créer un Map. Fonctionne dans toutes les versions de Scala.

val map = Map(seq map { a => a.key -> a }: _*)
40
Daniel Spiewak

Depuis 2.8 Scala a eu .toMap, alors:

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

ou si vous voulez éviter de construire une séquence intermédiaire de tuples:

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

Une autre variante de 2,8, pour faire bonne mesure, également efficace:

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

Notez que si vous avez des clés en double, vous en supprimerez certaines lors de la création de la carte! Vous pouvez utiliser groupBy pour créer une carte où chaque valeur est une séquence:

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

Comme scala sait convertir un Tuple de deux en une carte, vous voudriez d'abord convertir votre seq en Tuple et ensuite la mapper ainsi (peu importe si c'est int, dans notre cas chaîne, chaîne):

L'algorithme général est le suivant:

  1. Pour chaque article dans Seq
  2. Objet -> Tuple (clé, valeur)
  3. Pour chaque tuple (clé, valeur)
  4. Agréger vers la carte (clé, valeur)

Ou pour résumer:

Étape 1: Seq -> Tuple de deux

Étape 2: Tuple de deux -> Carte

Exemple:

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)
2
Tomer Ben David