Mempelajari Scala saat ini dan diperlukan untuk membalikkan Peta untuk melakukan beberapa pencarian nilai-> kunci. Saya sedang mencari cara sederhana untuk melakukan ini, tetapi hanya menemukan:
(Map() ++ origMap.map(kvp=>(kvp._2->kvp._1)))
Ada yang punya pendekatan yang lebih elegan?
scala
scala-collections
AlexeyMK
sumber
sumber
Map(1 -> "A", 2 -> "B", 3 -> "B").map(_.swap)
hasil dalamMap(A -> 1, B -> 3)
Secara matematis, pemetaan mungkin tidak dapat dibalik (injektif), misalnya, dari
Map[A,B]
, Anda tidak bisa mendapatkanMap[B,A]
, tetapi Anda mendapatkanMap[B,Set[A]]
, karena mungkin ada kunci berbeda yang terkait dengan nilai yang sama. Jadi, jika Anda tertarik untuk mengetahui semua kuncinya, berikut kodenya:sumber
.map(_._1)
akan lebih mudah dibaca karena hanya.keys
Set
s, bukanList
s seperti sebelumnya..mapValues
karena mengembalikan tampilan. Terkadang, ini yang Anda inginkan, tetapi jika Anda tidak berhati-hati, hal ini dapat menghabiskan banyak memori dan CPU. Untuk memaksanya menjadi peta, Anda bisa melakukannyam.groupBy(_._2).mapVaues(_.keys).map(identity)
, atau Anda bisa mengganti panggilan ke.mapValues(_.keys)
dengan.map { case (k, v) => k -> v.keys }
.Anda dapat menghindari barang ._1 sambil melakukan iterasi dengan beberapa cara.
Inilah salah satu caranya. Ini menggunakan fungsi parsial yang mencakup satu-satunya kasus yang penting untuk peta:
Berikut cara lain:
Iterasi peta memanggil fungsi dengan dua elemen tupel, dan fungsi anonim menginginkan dua parameter. Function.tupled membuat terjemahan.
sumber
Saya datang ke sini mencari cara untuk membalikkan Peta tipe Peta [A, Seq [B]] ke Peta [B, Seq [A]], di mana setiap B di peta baru dikaitkan dengan setiap A di peta lama untuk yang B terkandung dalam urutan terkait A.
Misalnya,
Map(1 -> Seq("a", "b"), 2-> Seq("b", "c"))
akan terbalik menjadi
Map("a" -> Seq(1), "b" -> Seq(1, 2), "c" -> Seq(2))
Inilah solusi saya:
di mana oldMap bertipe
Map[A, Seq[B]]
dan newMap bertipeMap[B, Seq[A]]
FoldLefts bersarang membuat saya sedikit ngeri, tetapi ini adalah cara paling mudah yang dapat saya temukan untuk mencapai jenis inversi ini. Ada yang punya solusi yang lebih bersih?
sumber
Map[A, Seq[B]]
untukMap[B, Seq[A]]
mana trasnforms solusi AndaMap[A, Seq[B]]
untukMap[Seq[B], Seq[A]]
.a.toSeq.flatMap { case (a, b) => b.map(_ -> a) }.groupBy(_._2).mapValues(_.map(_._1))
Oke, jadi ini adalah pertanyaan yang sangat lama dengan banyak jawaban yang bagus, tapi saya telah membangun
Map
inverter , pisau Swiss-Army, yang paling mutakhir , dan ini adalah tempat untuk mempostingnya.Ini sebenarnya dua inverter. Satu untuk elemen nilai individu ...
... dan satu lagi, sangat mirip, untuk koleksi nilai.
pemakaian:
Saya lebih suka memiliki kedua metode di kelas implisit yang sama tetapi semakin banyak waktu yang saya habiskan untuk melihatnya semakin bermasalah.
sumber
Anda bisa membalikkan peta menggunakan:
Masalah dengan pendekatan ini adalah jika nilai Anda, yang sekarang menjadi kunci hash di peta Anda, tidak unik, Anda akan membuang nilai duplikat. Menggambarkan:
Untuk menghindari hal ini, Anda dapat mengonversi peta Anda ke daftar tupel terlebih dahulu, kemudian membalikkan, sehingga Anda tidak menjatuhkan nilai duplikat:
sumber
Dalam skala REPL:
Perhatikan bahwa nilai duplikat akan ditimpa dengan tambahan terakhir pada peta:
sumber
Memulai
Scala 2.13
, untuk menukar kunci / nilai tanpa kehilangan kunci yang terkait dengan nilai yang sama, kita dapat menggunakan metode groupMapMap
baru , yang (seperti yang disarankan namanya) sama dengan a dan ping atas item yang dikelompokkan.groupBy
map
Ini:
group
s elemen berdasarkan tupel kedua mereka part (_._2
) (bagian grup dari peta grup )map
s item dikelompokkan dengan mengambil bagian tuple pertama mereka (_._1
) (map bagian dari kelompok Map )Ini dapat dilihat sebagai versi sekali jalan dari
map.groupBy(_._2).mapValues(_.map(_._1))
.sumber
Map[K, C[V]]
menjadiMap[V, C[K]]
.Pembalikan adalah nama yang lebih baik untuk operasi ini daripada kebalikan (seperti dalam "kebalikan dari fungsi matematika")
Saya sering melakukan transformasi terbalik ini tidak hanya pada peta tetapi pada koleksi lain (termasuk Seq). Menurut saya yang terbaik adalah tidak membatasi definisi operasi inversi saya pada peta satu-ke-satu. Berikut definisi yang saya operasikan untuk peta (harap sarankan perbaikan pada implementasi saya).
Jika ini adalah peta satu-ke-satu, Anda akan mendapatkan daftar tunggal yang dapat diuji dan ditransformasikan menjadi Peta [B, A] daripada Peta [B, Daftar [A]].
sumber
Kita dapat mencoba menggunakan
foldLeft
fungsi ini yang akan menangani tabrakan dan membalikkan peta dalam traversal tunggal.sumber