Слияние карт по ключу

Скажем, у меня есть две карты:

val a = Map(1 -> "one", 2 -> "two", 3 -> "three")
val b = Map(1 -> "un", 2 -> "deux", 3 -> "trois")

Я хочу объединить эти карты по ключу, применяя некоторую функцию для сбора значений (в этом конкретном случае я хочу собрать их в seq, давая:

val c = Map(1 -> Seq("one", "un"), 2 -> Seq("two", "deux"), 3 -> Seq("three", "trois"))

Такое ощущение, что должен быть хороший, идиоматический способ сделать это.

24
задан Xavier Guihot 8 June 2019 в 08:11
поделиться

3 ответа

val a = Map(1 -> "one", 2 -> "two", 3 -> "three")
val b = Map(1 -> "un", 2 -> "deux", 3 -> "trois")

val c = a.toList ++ b.toList
val d = c.groupBy(_._1).map{case(k, v) => k -> v.map(_._2).toSeq}
//res0: scala.collection.immutable.Map[Int,Seq[java.lang.String]] =
        //Map((2,List(two, deux)), (1,List(one, un), (3,List(three, trois)))
19
ответ дан 28 November 2019 в 22:48
поделиться

Так что я не был доволен ни одним из этих решений (я хочу создать новый тип, поэтому полугруппа на самом деле не чувствует себя уместно, а решение Infinity казалось довольно сложным), так что на данный момент я пошел с этим. Я был бы рад видеть, что это улучшилось:

def merge[A,B,C](a : Map[A,B], b : Map[A,B])(c : (B,B) => C) = {
  for (
    key <- (a.keySet ++ b.keySet);
    aval <- a.get(key); bval <- b.get(key)
  ) yield c(aval, bval)
}
merge(a,b){Seq(_,_)}

Я хотел, чтобы поведение ничего не возвращало, когда ключ не присутствовал ни на одной карте (что отличается от других решений), но был способ указать это было бы хорошо.

2
ответ дан 28 November 2019 в 22:48
поделиться
def merge[A,B,C,D](b : Map[A,B], c : Map[A,C])(d : (Option[B],Option[C]) => D): Map[A,D] = {
  (b.keySet ++ c.keySet).map(k => k -> d(b.get(k), c.get(k))).toMap
}

def optionSeqBiFunctionK[A]:(Option[A], Option[A]) => Seq[A] = _.toSeq ++ _.toSeq

merge(a,b)(optionSeqBiFunctionK)

0
ответ дан 28 November 2019 в 22:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: