Изучая Scala в настоящее время, необходимо инвертировать карту, чтобы выполнить поиск по инвертированному значению-> ключу. Я искал простой способ сделать это, но нашел только:
(Map() ++ origMap.map(kvp=>(kvp._2->kvp._1)))
У кого-нибудь есть более элегантный подход?
scala
scala-collections
АлексейМК
источник
источник
Map(1 -> "A", 2 -> "B", 3 -> "B").map(_.swap)
результатMap(A -> 1, B -> 3)
Математически сопоставление может быть необратимым (инъективным), например, от
Map[A,B]
, вы не можете получитьMap[B,A]
, а скорее получитеMap[B,Set[A]]
, потому что могут быть разные ключи, связанные с одними и теми же значениями. Итак, если вам интересно узнать все ключи, вот код:источник
.map(_._1)
было бы более разборчиво, как просто.keys
Set
s вместоList
s, как раньше..mapValues
потому что он возвращает представление. Иногда это именно то, что вам нужно, но если вы не будете осторожны, это может потреблять много памяти и процессора. Для того, чтобы заставить его в карту, вы можете сделатьm.groupBy(_._2).mapVaues(_.keys).map(identity)
, или вы могли бы заменить вызов.mapValues(_.keys)
с.map { case (k, v) => k -> v.keys }
.Вы можете избежать файлов ._1 при повторении несколькими способами.
Вот один способ. Здесь используется частичная функция, охватывающая единственный случай, имеющий значение для карты:
Вот еще один способ:
Итерация карты вызывает функцию с двухэлементным кортежем, а анонимной функции нужны два параметра. Function.tupled выполняет перевод.
источник
Я пришел сюда в поисках способа инвертировать карту типа Map [A, Seq [B]] в Map [B, Seq [A]], где каждый B в новой карте связан с каждым A в старой карте для который B содержался в связанной последовательности.
Например,
Map(1 -> Seq("a", "b"), 2-> Seq("b", "c"))
преобразовал бы в
Map("a" -> Seq(1), "b" -> Seq(1, 2), "c" -> Seq(2))
Вот мое решение:
где oldMap имеет тип,
Map[A, Seq[B]]
а newMap имеет типMap[B, Seq[A]]
Вложенные foldLefts заставляют меня немного съеживаться, но это самый простой способ, который я мог найти для выполнения такого типа инверсии. У кого-нибудь есть более чистое решение?
источник
Map[A, Seq[B]]
кMap[B, Seq[A]]
где ваши trasnforms решенияMap[A, Seq[B]]
дляMap[Seq[B], Seq[A]]
.a.toSeq.flatMap { case (a, b) => b.map(_ -> a) }.groupBy(_._2).mapValues(_.map(_._1))
Хорошо, это очень старый вопрос, на который есть много хороших ответов, но я создал идеальный, универсальный швейцарский армейский нож,
Map
инвертор, и это место, чтобы его опубликовать.Фактически это два инвертора. Один для отдельных элементов значения ...
... и еще один, очень похожий, для коллекций значений.
использование:
Я бы предпочел, чтобы оба метода были в одном неявном классе, но чем больше времени я тратил на его изучение, тем более проблематичным это казалось.
источник
Вы можете инвертировать карту, используя:
Проблема с этим подходом заключается в том, что если ваши значения, которые теперь стали хэш-ключами на вашей карте, не уникальны, вы удалите повторяющиеся значения. Проиллюстрировать:
Чтобы избежать этого, вы можете сначала преобразовать свою карту в список кортежей, а затем инвертировать, чтобы не отбрасывать повторяющиеся значения:
источник
В scala REPL:
Обратите внимание, что повторяющиеся значения будут перезаписаны последним добавлением к карте:
источник
Для начала
Scala 2.13
, чтобы поменять местами ключи / значения без потери ключей, связанных с одними и теми же значениями, мы можем использоватьMap
новый метод groupMap , который (как следует из названия) является эквивалентом agroupBy
иmap
ping для сгруппированных элементов.Это:
group
s элементов на основе их второй части кортежа (_._2
) (групповая часть групповой карты)map
s сгруппированные элементы, взяв их первую часть кортежа (_._1
) (часть карты группы Map )Это можно рассматривать как вариант однопроходной из
map.groupBy(_._2).mapValues(_.map(_._1))
.источник
Map[K, C[V]]
вMap[V, C[K]]
.Инверсия - лучшее название для этой операции, чем обратная (как в «инверсии математической функции»).
Я часто делаю это обратное преобразование не только на картах, но и на других коллекциях (включая Seq). Я считаю, что лучше не ограничивать определение моей обратной операции однозначными картами. Вот определение, с которым я работаю для карт (пожалуйста, предложите улучшения в моей реализации).
Если это взаимно однозначная карта, вы получите одноэлементные списки, которые можно тривиально протестировать и преобразовать в карту [B, A], а не в карту [B, List [A]].
источник
Мы можем попробовать использовать эту
foldLeft
функцию, которая позаботится о столкновениях и инвертирует карту за один проход.источник