Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala groupby key sum value over a Seq of (key, value) while maintaining Order

I am trying to resolve a problem with grouping and summing over scala tuples and maintaining the order of keys.

Say,

val arrayTuples = Array((A, 38) , (B, 150), (B, 250), (B, 890), (D, 600), (C, 515))

to

Map(A -> 38, B -> 1290, D -> 600, C -> 515)

Doing:

val aMap = arrayTuples .groupBy(_._1)

seems to mess with the ordering. Help appreciated.

EDIT: Maintain Ordering of first encountered.

like image 491
irrelevantUser Avatar asked Apr 25 '19 08:04

irrelevantUser


2 Answers

You can use a ListMap to preserve order, but if you want the left-to-right order-as-encountered, as requested in the comments, some extra steps are needed.

//note the new order of elements
val arrayTuples =
  Array(('A', 38), ('B', 150), ('D', 600), ('B', 250), ('C', 515), ('B', 890))

import collection.immutable.ListMap

arrayTuples.foldRight(ListMap[Char,Int]()) {
  case ((c,n), lm) => lm.updated(c , lm.getOrElse(c, 0)+n)
}.foldRight(ListMap[Char,Int]()){case (elem,lm) => lm+elem}
//res0: ListMap[Char,Int] = ListMap(A -> 38, B -> 1290, D -> 600, C -> 515)

Because ListMap preserves the order of last-enountered, which in this case would move the B entry to the end, I decided to foldRight, which moves the A entry to the end, and then foldRight again to reverse the whole thing.

like image 101
jwvh Avatar answered Nov 17 '22 21:11

jwvh


You can get an insertion ordered map like this:

import scala.collection.immutable.ListMap

val tuples = List(("A", 38) , ("B", 150), ("B", 250), ("B", 890), ("C", 515), ("D", 600))

val initMap = ListMap.empty[String, List[(String, Int)]].withDefaultValue(List.empty)

val aMap = tuples.foldLeft(initMap) { case (acc, (k, v)) =>
  val newList = (k -> v) :: acc(k)
  acc + (k -> newList)
}

println(aMap) // Map(A -> List((A,38)), B -> List((B,890), (B,250), (B,150)), C -> List((C,515)), D -> List((D,600)))
like image 3
insan-e Avatar answered Nov 17 '22 20:11

insan-e