Si j'ai une collection c
de type T
et qu'il y a une propriété p
sur T
(de type P
, par exemple), quelle est la meilleure façon de faire une carte par clé d'extraction ?
val c: Collection[T]
val m: Map[P, T]
Une façon est la suivante:
m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }
Mais maintenant, j'ai besoin d'une carte mutable . Y a-t-il une meilleure façon de faire cela pour que ce soit sur 1 ligne et que je me retrouve avec une carte immuable ? (Évidemment, je pourrais transformer ce qui précède en un simple utilitaire de bibliothèque, comme je le ferais en Java, mais je soupçonne que dans Scala, ce n'est pas nécessaire)
scala
map
scala-collections
oxbow_lakes
la source
la source
Traversable[K].mapTo( K => V)
etTraversable[V].mapBy( V => K)
c'était mieux!c
parc.iterator
pour éviter la création d'une collection intermédiaire.Vous pouvez construire une carte avec un nombre variable de tuples. Utilisez donc la méthode map sur la collection pour la convertir en une collection de tuples, puis utilisez l'astuce: _ * pour convertir le résultat en argument variable.
la source
En plus de la solution de @James Iry, il est également possible d'accomplir cela en utilisant un pli. Je soupçonne que cette solution est légèrement plus rapide que la méthode tuple (moins d'objets garbage sont créés):
la source
list.foldLeft(Map[String,Int]()) { (m,s) => m + (s -> s.length) }
. Notez que si vous souhaitez utiliser des virgules pour construire le tuple, vous avez besoin d' une paire de parenthèses:((s, s.length))
.Cela peut être implémenté de manière immuable et avec un seul parcours en repliant la collection comme suit.
La solution fonctionne car l'ajout à une carte immuable retourne une nouvelle carte immuable avec l'entrée supplémentaire et cette valeur sert d'accumulateur via l'opération de repli.
Le compromis ici est la simplicité du code par rapport à son efficacité. Ainsi, pour les grandes collections, cette approche peut être plus appropriée que l'utilisation de 2 implémentations de traversée telles que l'application
map
ettoMap
.la source
Une autre solution (peut ne pas fonctionner pour tous les types)
cela évite la création de la liste intermédiaire, plus d'infos ici: Scala 2.8 breakOut
la source
Ce que vous essayez d'atteindre est un peu indéfini.
Que faire si deux ou plusieurs éléments
c
partagent le mêmep
? Quel élément sera mappé à celuip
de la carte?La façon la plus précise de voir cela est de produire une carte entre
p
et tous lesc
éléments qui la contiennent:Cela pourrait être facilement réalisé avec groupBy :
Si vous voulez toujours la carte d'origine, vous pouvez, par exemple, mapper
p
sur la premièret
qui la possède:la source
collect
place demap
. Par exemple:c.group(t => t.p) collect { case (Some(p), ts) => p -> ts.head }
. De cette façon, vous pouvez faire des choses comme aplatir les cartes lorsque vous tapez une option [_]..mapValues(_.head)
place de la carte.Ce n'est probablement pas le moyen le plus efficace de transformer une liste en carte, mais cela rend le code d'appel plus lisible. J'ai utilisé des conversions implicites pour ajouter une méthode mapBy à List:
Exemple de code d'appel:
Notez qu'en raison de la conversion implicite, le code de l'appelant doit importer implicitConversions de scala.
la source
Fonctionne bien et est très intuitif
la source
c
comme clé (en quelque sorte). Notez "map" car la collection résultante n'est pas une scalaMap
mais crée une autre liste / itérable de tuples ... mais l'effet est le même pour le but de l'OP, je n'écarterais pas la simplicité mais ce n'est pas aussi efficace que lafoldLeft
solution, ni la vraie réponse à la question "convertir en une collection en une carte par clé"Que diriez-vous d'utiliser zip et toMap?
la source
Pour ce que ça vaut, voici deux façons inutiles de le faire:
la source
Map.fromList $ map (bar &&& id) c
,Map.fromList $ map (bar >>= (,)) c
.Cela fonctionne pour moi:
La carte doit être mutable et la carte doit être retournée car l'ajout à une carte mutable ne renvoie pas de carte.
la source
val personsMap = persons.foldLeft(Map[Int, PersonDTO]()) { (m, p) => m + (p.id -> p) }
La carte peut être immuable, comme indiqué ci-dessus, car l'ajout à une carte immuable renvoie une nouvelle carte immuable avec l'entrée supplémentaire. Cette valeur sert d'accumulateur pendant l'opération de pliage.utiliser map () sur la collection suivi de toMap
la source
En cas de conversion de Json String (lecture d'un fichier json) en scala Map
la source