Scala meilleur moyen de transformer une Collection sur une Carte-par-clé?
Si j'ai une collection c
de type T
et il y a une propriété p
sur T
(de type P
, par exemple), quel est le meilleur moyen de faire un la carte-par extraction-clés?
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'un mutable carte. Est-il une meilleure manière de faire ceci, de sorte que c'est en 1 ligne et je me retrouve avec un immuable Carte? (Évidemment, je pouvais tourner la ci-dessus en un simple bibliothèque de l'utilitaire, comme je le ferais en Java, mais je soupçonne que, dans la Scala, il n'est pas nécessaire)
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser
mais sachez que ce besoin de 2 traversals.
Traversable[K].mapTo( K => V)
etTraversable[V].mapBy( V => K)
ont été mieux!c map (_.getP) zip c toMap
c
avecc.iterator
pour éviter la création de collecte intermédiaires.Iterator[(P,T)] does not take parameters
. Toutefois, les deux suggestions de travail en Scala 2.11.Vous pouvez construire une Carte avec un nombre variable de n-uplets. Il faut donc utiliser la méthode map sur la collection de le transformer en une collection de n-uplets et ensuite utiliser le : _* astuce pour convertir le résultat dans une variable d'argument.
En plus de @James Iri de la solution, il est également possible de le faire à l'aide d'un pli. Je soupçonne que cette solution est un peu plus rapide que le n-uplet de la méthode (moins de déchets de la création d'objets):
list.foldLeft(Map[String, Int]()) { (m, s) => m(s) = s.length; m }
Également désolé pour 10 mois trop tard 🙂list.foldLeft(Map[String,Int]()) { (m,s) => m + (s -> s.length) }
. Notez que si vous souhaitez utiliser la virgule pour construire le tuple, vous avez besoin d'une paire de parenthèses:((s, s.length))
.Cela peut être mis en œuvre immuablement et avec une seule traversée par pliage à travers la collection comme suit.
La solution fonctionne parce que l'ajout d'un immuable la Carte renvoie une nouvelle immuable Carte avec l'entrée supplémentaire et cette valeur sert de l'accumulateur par le pli de l'opération.
La différence ici, c'est la simplicité du code par rapport à son efficacité. Donc, pour les grandes collections, cette approche peut être plus appropriée à l'aide de 2 traversée implémentations telles que l'application
map
ettoMap
.Une autre solution (peut ne pas fonctionner pour tous les types)
cela évite la création de l'intermédiaire de la liste, plus d'info ici:
Scala 2.8 breakOut
Ce que vous essayez d'atteindre est un peu indéfini.
Si deux ou plusieurs éléments dans
c
partagent le mêmep
? L'article qui sera affecté à cettep
dans la carte?Le plus précis de façon de voir les choses est ce qui donne une carte entre
p
et tous lesc
éléments que l'ont:Cela peut être facilement réalisé avec groupBy:
Si vous voulez toujours la carte d'origine, vous pouvez, par exemple, la carte
p
pour la premièret
qui a il:collect
au lieu 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 entrez une Option[_]..mapValues(_.head)
au lieu de la carte.Ce n'est probablement pas le moyen le plus efficace pour transformer une liste de carte, mais il fait l'appel code plus lisible. J'ai utilisé des conversions implicites pour ajouter un mapBy méthode de la Liste:
Code appelant exemple:
Noter qu'en raison de la conversion implicite, l'appelant code doit importer la scala, à la implicitConversions.
Fonctionne bien et est très intuitiv
c
comme clé de tri (de). Remarque "à la carte", car la collection n'est pas un scalaMap
mais en crée une autre liste/itératif de tuples...mais l'effet est le même pour l'OP du but, je ne serait pas remise de la simplicité, mais il n'est pas aussi efficace quefoldLeft
solution, ni que c'est la vraie réponse à la question "à le transformer en une collection sur une carte-par-clé"Pour ce que ça vaut, ici, sont deux inutile façons de le faire:
Map.fromList $ map (bar &&& id) c
,Map.fromList $ map (bar >>= (,)) c
.Comment sur l'utilisation de zip et toMap?
Cela fonctionne pour moi:
La Carte doit être mutable et la Carte doit être de retour depuis l'ajout d'une mutable Carte ne prend pas en retour une carte.
val personsMap = persons.foldLeft(Map[Int, PersonDTO]()) { (m, p) => m + (p.id -> p) }
La Carte peut être immuable, comme démontré ci-dessus, car l'ajout d'une immuable la Carte renvoie une nouvelle immuable Carte avec l'entrée supplémentaire. Cette valeur sert de l'accumulateur par le pli de l'opération.utilisation de la carte() sur la collecte de suivi avec toMap