I have two lists in Scala, how to merge them such that the tuples are grouped together?
Is there an existing Scala list API which can do this or need I do it by myself?
Input:
List((a,4), (b,1), (c,1), (d,1))
List((a,1), (b,1), (c,1))
Expected output:
List((a,5),(b,2),(c,2),(d,1))
You can try the following one-line:
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))
Where l1
and l2
are the lists of tuples you want merge.
Now, the breakdown:
(l1 ++ l2)
you just concatenate both lists.groupBy( _._1)
you group all tuples by their first element. You will receive a Map with
the first element as key and lists of tuples starting with this element as values..map( kv => (kv._1, kv._2.map( _._2).sum ) )
you make a new map, with similar keys, but the values are the sum of all second elements..toList
you convert the result back to a list.Alternatively, you can use pattern matching to access the tuple elements.
( l1 ++ l2 ).groupBy( _._1 ).map{
case (key,tuples) => (key, tuples.map( _._2).sum )
}.toList
Alternatively you can also use mapValues
to shorten the code.
mapValues
, as you can probably guess, allows you to re-map just the value for each (key, value) pair in the Map created by groupBy
.
In this case the function passed to mapValues
reduces each (Char, Int) tuple to just the Int then sums the resulting List of Ints.
(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList
If the order of the output list needs to follow your example, just add sorted
which relies on an Ordering[(Char, Int)] implicit instance.
(l1 ::: l2).groupBy(_._1).mapValues(_.map(_._2).sum).toList.sorted
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With