Как объединить два списка кортежей?
у меня есть два списка в Scala, как объединить их так, чтобы кортежи были сгруппированы вместе?
есть ли существующий API списка Scala, который может это сделать или мне нужно сделать это самостоятельно?
вход:
List((a,4), (b,1), (c,1), (d,1))
List((a,1), (b,1), (c,1))
ожидаемый результат:
List((a,5),(b,2),(c,2),(d,1))
3 ответов
вы можете попробовать следующие одну строку:
scala> ( l1 ++ l2 ).groupBy( _._1 ).map( kv => (kv._1, kv._2.map( _._2).sum ) ).toList
res6: List[(Symbol, Int)] = List(('a,5), ('c,2), ('b,2), ('d,1))
здесь l1
и l2
списки кортежей, которые вы хотите объединить.
теперь поломки:
-
(l1 ++ l2)
вы просто объединяете оба списка -
.groupBy( _._1)
сгруппировать все Кортежи по их первому элементу. Вы получите карту с первый элемент в качестве ключа и список кортежей, начиная с этого элемента в качестве значения. -
.map( kv => (kv._1, kv._2.map( _._2).sum ) )
вы делаете новую карту, с аналогичными ключи, но значения являются суммой всех вторых элементов. -
.toList
преобразовать результат обратно в список.
кроме того, вы можете использовать сопоставление шаблонов для доступа к элементам кортежа.
( l1 ++ l2 ).groupBy( _._1 ).map{
case (key,tuples) => (key, tuples.map( _._2).sum )
}.toList
в качестве альтернативы вы можете также использовать mapValues
для сокращения кода.
mapValues
, Как вы, вероятно, догадываетесь, позволяет повторно отобразить только значение для каждой пары (ключ, значение) в карте, созданной groupBy
.
в этом случае функция передается в mapValues
уменьшает каждый (Char, Int) Кортеж только до Int, а затем суммирует результирующий список Ints.
(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList
если порядок списка вывода должен следовать вашему примеру, просто добавьте sorted
, который опирается на Упорядочение [(Char, Int)] неявного экземпляра.
(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList.sorted
Если вы можете предположить, что оба List[(A,B)]
упорядочены в соответствии с Ordering[A]
, вы можете написать что-то вроде:
def mergeLists[A,B](one:List[(A,B)], two:List[(A,B)])(op:(B,B)=>B)(implicit ord:Ordering[A]): List[(A,B)] = (one,two) match {
case (xs, Nil) => xs
case (Nil, ys) => ys
case((a,b)::xs,(aa,bb)::ys) =>
if (a == aa) (a, op(b,bb)) :: mergeLists(xs,ys)(op)(ord)
else if (ord.lt(a,aa)) (a, b) :: mergeLists(xs, (aa,bb)::ys)(op)(ord)
else (aa, bb) :: mergeLists((a,b) :: xs, ys)(op)(ord)
}
к сожалению, это не хвост рекурсивной.