sethu
sethu

Reputation: 8431

Scala Sum of Values of a Map

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!

Upvotes: 3

Views: 5007

Answers (3)

Sven Koschnicke
Sven Koschnicke

Reputation: 6711

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)

Upvotes: 7

slouc
slouc

Reputation: 9698

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)

Upvotes: 4

barczajozsef
barczajozsef

Reputation: 483

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

Upvotes: 0

Related Questions