Lernen Sie Scala aktuell und müssen Sie eine Karte invertieren, um einige invertierte Wert-> Schlüsselsuchen durchzuführen. Ich suchte nach einem einfachen Weg, aber ich fand nur:
(Map() ++ origMap.map(kvp=>(kvp._2->kvp._1)))
Hat jemand einen eleganteren Ansatz?
scala
scala-collections
AlexeyMK
quelle
quelle
Map(1 -> "A", 2 -> "B", 3 -> "B").map(_.swap)
ergibt sichMap(A -> 1, B -> 3)
Mathematisch gesehen ist die Zuordnung möglicherweise nicht invertierbar (injektiv), z. B. von
Map[A,B]
, Sie können nicht erhaltenMap[B,A]
, sondern Sie erhaltenMap[B,Set[A]]
, weil möglicherweise unterschiedliche Schlüssel mit denselben Werten verknüpft sind. Wenn Sie also alle Schlüssel kennen möchten, finden Sie hier den Code:quelle
.map(_._1)
wäre mehr lesbar als nur.keys
Set
s anstelle vonList
s erhalten..mapValues
da eine Ansicht zurückgegeben wird. Gelegentlich ist dies das, was Sie wollen, aber wenn Sie nicht aufpassen, kann es viel Speicher und CPU verbrauchen. Um es in eine Karte zu erzwingen, können Sie tunm.groupBy(_._2).mapVaues(_.keys).map(identity)
, oder Sie können den Anruf ersetzen.mapValues(_.keys)
mit.map { case (k, v) => k -> v.keys }
.Sie können das ._1-Zeug vermeiden, während Sie auf verschiedene Arten iterieren.
Hier ist eine Möglichkeit. Dies verwendet eine Teilfunktion, die den einzigen Fall abdeckt, der für die Karte von Bedeutung ist:
Hier ist ein anderer Weg:
Die Karteniteration ruft eine Funktion mit einem Tupel mit zwei Elementen auf, und die anonyme Funktion möchte zwei Parameter. Function.tupled macht die Übersetzung.
quelle
Ich bin hierher gekommen, um nach einer Möglichkeit zu suchen, eine Karte vom Typ Karte [A, Seq [B]] in Karte [B, Seq [A]] umzukehren, wobei jedes B in der neuen Karte jedem A in der alten Karte für zugeordnet ist welches das B in A's assoziierter Sequenz enthalten war.
ZB
Map(1 -> Seq("a", "b"), 2-> Seq("b", "c"))
würde sich umkehren
Map("a" -> Seq(1), "b" -> Seq(1, 2), "c" -> Seq(2))
Hier ist meine Lösung:
Dabei ist oldMap vom Typ
Map[A, Seq[B]]
und newMap vom TypMap[B, Seq[A]]
Die verschachtelten FoldLefts lassen mich ein wenig zusammenzucken, aber dies ist der einfachste Weg, um diese Art der Inversion zu erreichen. Hat jemand eine sauberere Lösung?
quelle
Map[A, Seq[B]]
zu ,Map[B, Seq[A]]
wo Ihre Lösung trasnformsMap[A, Seq[B]]
zuMap[Seq[B], Seq[A]]
.a.toSeq.flatMap { case (a, b) => b.map(_ -> a) }.groupBy(_._2).mapValues(_.map(_._1))
OK, das ist also eine sehr alte Frage mit vielen guten Antworten, aber ich habe das ultimative Schweizer Taschenmesser, den
Map
Wechselrichter, gebaut und hier kann ich es posten.Es sind eigentlich zwei Wechselrichter. Eine für einzelne Wertelemente ...
... und eine andere, ganz ähnliche, für Wertsammlungen.
Verwendung:
Ich würde es vorziehen, beide Methoden in derselben impliziten Klasse zu haben, aber je mehr Zeit ich damit verbrachte, sie zu untersuchen, desto problematischer erschien sie.
quelle
Sie können eine Karte invertieren, indem Sie:
Das Problem bei diesem Ansatz besteht darin, dass Sie die doppelten Werte löschen, wenn Ihre Werte, die jetzt zu den Hash-Schlüsseln in Ihrer Karte geworden sind, nicht eindeutig sind. Um zu zeigen:
Um dies zu vermeiden, können Sie Ihre Karte zuerst in eine Liste von Tupeln konvertieren und dann invertieren, damit Sie keine doppelten Werte löschen:
quelle
In scala REPL:
Beachten Sie, dass doppelte Werte beim letzten Hinzufügen zur Karte überschrieben werden:
quelle
Starten
Scala 2.13
, um die Swap - Schlüssel / Werte ohne Schlüssel zugeordnet gleichen Werte zu verlieren, wir könnenMap
neue s groupMap Methode, die (wie der Name schon sagt) ist ein Äquivalent einesgroupBy
und einmap
Ping über gruppierte Elemente.Dies:
group
s Elemente basierend auf ihrem zweiten Tupelteil (_._2
) (Gruppenteil der Gruppenzuordnung )map
gruppierten Elemente s mit ihrem ersten Tupel Teil unter (_._1
) (Teil der Gruppe Karte Karte )Dies kann als One-Pass-Version von angesehen werden
map.groupBy(_._2).mapValues(_.map(_._1))
.quelle
Map[K, C[V]]
wirdMap[V, C[K]]
.Inverse ist ein besserer Name für diese Operation als Reverse (wie in "Inverse einer mathematischen Funktion").
Ich mache diese inverse Transformation oft nicht nur auf Karten, sondern auch auf anderen (einschließlich Seq) Sammlungen. Ich finde es am besten, die Definition meiner inversen Operation nicht auf Eins-zu-Eins-Karten zu beschränken. Hier ist die Definition, mit der ich für Karten arbeite (bitte schlagen Sie Verbesserungen für meine Implementierung vor).
Wenn es sich um eine Eins-zu-Eins-Karte handelt, erhalten Sie Singleton-Listen, die trivial getestet und in eine Karte [B, A] anstatt in eine Karte [B, Liste [A]] umgewandelt werden können.
quelle
Wir können versuchen, diese
foldLeft
Funktion zu verwenden, die Kollisionen beseitigt und die Karte in einer einzelnen Durchquerung invertiert.quelle