3

New to scala .. I wanted to calculate the sum of all elements in List which is a value of a map.

case class Test(shareClass:String, noOfShares:Long){}

val list = new Test("a", 10)::new Test("b",20)::new Test("a",30)::new Test("b", 5)::Nil

I wanted to creates a Map of
a -> 40
b -> 25

I understand I can use group by on the list which will give me a list of test values, but I am not sure how to operate on that.

Thanks!

sethu
  • 8,181
  • 7
  • 39
  • 65

3 Answers3

7

Using groupBy creates a Map where the values are a list of all matching objects:

scala> list.groupBy(_.shareClass)
res0: scala.collection.immutable.Map[String,List[Test]] = Map(b -> List(Test(b,20), Test(b,5)), a -> List(Test(a,10), Test(a,30)))

From there you can use mapValues to transform the values of the map, first selecting the noOfShares attribute and then sum these:

scala> list.groupBy(_.shareClass).mapValues(_.map(_.noOfShares).sum)
res1: scala.collection.immutable.Map[String,Long] = Map(b -> 25, a -> 40)

Note that mapValues only creates a view on the original Map, this means the _.map(_.noOfShares).sum-part is applied every time the result is accessed (even when assigning it to a val before). To get a plain Map with only the result, you can call view.force on it:

scala> list.groupBy(_.shareClass).mapValues(_.map(_.noOfShares).sum).view.force
res2: scala.collection.immutable.Map[String,Long] = Map(b -> 25, a -> 40)
Community
  • 1
  • 1
Sven Koschnicke
  • 6,523
  • 2
  • 34
  • 49
  • 2
    Note that the `Map` created by `mapValues` recalculates values on each access: http://stackoverflow.com/questions/14882642/scala-why-mapvalues-produces-a-view-and-is-there-any-stable-alternatives – Alexey Romanov Apr 04 '16 at 14:46
  • Thank you @AlexeyRomanov! I didn't know that! I added it it the answer. – Sven Koschnicke Apr 05 '16 at 07:06
4

Here you go.

case class Test(shareClass: String, noOfShares: Long) {}

val list = new Test("a", 10) :: new Test("b", 20) :: new Test("a", 30) :: new Test("b", 5) :: Nil

val list2 = list.groupBy((_.shareClass))
  .map({ case (a, b) => (a, b.map(_.noOfShares).sum) })

println((list2)) // Map(b -> 25, a -> 40)
slouc
  • 9,508
  • 3
  • 16
  • 41
0
case class Test(shareClass: String, noOfShares: Long) {}

  val list = Test("a", 10) :: Test("b", 20) :: Test("a", 30) :: Test("b", 5) :: Nil

  println(list.groupBy(_.shareClass).map(test => (test._1 -> test._2.foldLeft(0L)((o, n) => o + n.noOfShares))))

first, you create groups with groupBy like this:

Map(b -> List(Test(b,20), Test(b,5)), a -> List(Test(a,10), Test(a,30)))

after that you convert the element's values to the sum of Test's noOfShares

barczajozsef
  • 473
  • 5
  • 11