Apprentissage de Scala actuellement et nécessaire pour inverser une carte pour faire des recherches de valeurs inversées> clés. Je cherchais un moyen simple de le faire, mais je n'ai proposé que:
(Map() ++ origMap.map(kvp=>(kvp._2->kvp._1)))
Quelqu'un a-t-il une approche plus élégante?
scala
scala-collections
AlexeyMK
la source
la source
Map(1 -> "A", 2 -> "B", 3 -> "B").map(_.swap)
résultats sontMap(A -> 1, B -> 3)
Mathématiquement, le mappage peut ne pas être inversible (injectif), par exemple, à partir de
Map[A,B]
, vous ne pouvez pas obtenirMap[B,A]
, mais plutôt vous obtenezMap[B,Set[A]]
, car il peut y avoir différentes clés associées aux mêmes valeurs. Donc, si vous souhaitez connaître toutes les clés, voici le code:la source
.map(_._1)
serait plus legibile que juste.keys
Set
s au lieu deList
s comme auparavant..mapValues
car il renvoie une vue. Parfois, c'est ce que vous voulez, mais si vous ne faites pas attention, cela peut consommer beaucoup de mémoire et de processeur. Pour le forcer dans une carte, vous pouvez le fairem.groupBy(_._2).mapVaues(_.keys).map(identity)
, ou vous pouvez remplacer l'appel à.mapValues(_.keys)
par.map { case (k, v) => k -> v.keys }
.Vous pouvez éviter les éléments ._1 lors de l'itération de plusieurs façons.
Voici un moyen. Cela utilise une fonction partielle qui couvre le seul et unique cas qui compte pour la carte:
Voici une autre façon:
L'itération de la carte appelle une fonction avec un tuple à deux éléments et la fonction anonyme veut deux paramètres. Function.tupled effectue la traduction.
la source
Je suis venu ici à la recherche d'un moyen d'inverser une carte de type Map [A, Seq [B]] en Map [B, Seq [A]], où chaque B de la nouvelle carte est associé à chaque A de l'ancienne carte pour dont le B était contenu dans la séquence associée de A.
Par exemple,
Map(1 -> Seq("a", "b"), 2-> Seq("b", "c"))
inverserait
Map("a" -> Seq(1), "b" -> Seq(1, 2), "c" -> Seq(2))
Voici ma solution:
où oldMap est de type
Map[A, Seq[B]]
et newMap est de typeMap[B, Seq[A]]
Les plis imbriqués me font un peu grincer des dents, mais c'est le moyen le plus simple que je puisse trouver pour accomplir ce type d'inversion. Quelqu'un a-t-il une solution plus propre?
la source
Map[A, Seq[B]]
àMap[B, Seq[A]]
où votre solution trasnformsMap[A, Seq[B]]
àMap[Seq[B], Seq[A]]
.a.toSeq.flatMap { case (a, b) => b.map(_ -> a) }.groupBy(_._2).mapValues(_.map(_._1))
OK, c'est donc une très vieille question avec de nombreuses bonnes réponses, mais j'ai construit l'ultime, le couteau suisse, l'
Map
onduleur et c'est ici qu'il faut l'afficher.Il s'agit en fait de deux onduleurs. Un pour les éléments de valeur individuels ...
... et un autre, assez similaire, pour les collections de valeur.
usage:
Je préférerais avoir les deux méthodes dans la même classe implicite, mais plus je passais de temps à l'examiner, plus elle apparaissait problématique.
la source
Vous pouvez inverser une carte en utilisant:
Le problème avec cette approche est que si vos valeurs, qui sont maintenant devenues les clés de hachage de votre carte, ne sont pas uniques, vous supprimerez les valeurs en double. Pour illustrer:
Pour éviter cela, vous pouvez d'abord convertir votre carte en une liste de tuples, puis inverser, afin de ne supprimer aucune valeur en double:
la source
Dans scala REPL:
Notez que les valeurs en double seront écrasées par le dernier ajout à la carte:
la source
Pour commencer
Scala 2.13
, pour échanger les clés / valeurs sans perdre les clés associées aux mêmes valeurs, nous pouvons utiliser laMap
nouvelle méthode groupMap , qui (comme son nom l'indique) est l'équivalent d'ungroupBy
et d'unmap
ping sur des éléments groupés.Ce:
group
s éléments basés sur leur deuxième partie de tuple (_._2
) (partie de groupe du groupe Map)map
s éléments groupés en prenant leur première partie de tuple (_._1
) (partie map du groupe Map )Cela peut être considéré comme une version en un seul passage de
map.groupBy(_._2).mapValues(_.map(_._1))
.la source
Map[K, C[V]]
enMap[V, C[K]]
.Inverse est un meilleur nom pour cette opération que reverse (comme dans "inverse d'une fonction mathématique")
Je fais souvent cette transformation inverse non seulement sur des cartes mais sur d'autres collections (y compris Seq). Je trouve préférable de ne pas limiter la définition de mon opération inverse aux cartes un-à-un. Voici la définition avec laquelle j'opère pour les cartes (veuillez suggérer des améliorations à mon implémentation).
Si c'est une carte un-à-un, vous vous retrouvez avec des listes de singleton qui peuvent être testées de manière triviale et transformées en une carte [B, A] plutôt qu'en une carte [B, Liste [A]].
la source
Nous pouvons essayer d'utiliser cette
foldLeft
fonction qui prendra en charge les collisions et inversera la carte en un seul parcours.la source