cgt
cgt

Reputation: 1

Adding Lists in Scala based on specified values

I am working on Scala at a beginner level.

I have the following lists

List_1=List((2.0,0), (4.5,1), (1.2,1), (3.0,3), (4.4,1), (4.5,0), (1.7,0), (5.3,2), (2.0,3))
List_2=List(0,1,2,3)

I want to add all first values from List_1 which are paired with numbers between 0 and 3. I tried (List_1.filter(_._2==0).map(e=>e._1)) and get 2.0, 4.5 and 1.7 and their sum is 8.2. By repeating for 1,2,3 i want to get a result like this (8.2,10.1,5.3,5.0).
Can anybody give me an idea to proceed?

Upvotes: 0

Views: 88

Answers (3)

Sebastian Celestino
Sebastian Celestino

Reputation: 1428

In order to do what you need you can use groupBy

val list = List( (2.0,0), (4.5,1), (1.2,1), (3.0,3), (4.4,1), (4.5, 0), (1.7,0), (5.3,2), (2.0,3) )

val result = list.groupBy { case (_, key) => key }.toList.sortBy { case (key, _) => key }.map { case (_, values) => values.map { case (value, _) => value }.sum }

First you group by your key (from 0 to 3), you get a Map[Int, List[(Double, Int)]. Then you can sort them by your key (if you want your result ordered), and finally transform each element in the sum of its values.

This is a shortest way but I prefer the first one (it is more expressive)

val r = list.groupBy(_._2).toList.sortBy(_._1).map(_._2.map(_._1).sum)

Upvotes: 0

Dima
Dima

Reputation: 40510

You can actually write it quite literally in scala:

(0 to 3).map { n => 
   list.collect { case (x, `n`) => x }.sum 
}

Note the "backticks" around n in the case clause. This means "match only tuples where second element equals to n". Without backticks in this context, it would mean "create a new local variable n, and assigned the second element of the tuple to it".

Alternatively, with a little more effort, you could compute all four sums in one pass through the list (which could save you some time, if there were, say, thousand of sums, rather than four, and the list had a few million elements in it):

list.foldLeft(Map.empty[Int, Double]) { case (result, (value, n)) => 
   result + (n -> (result.getOrElse(n, 0.0) + value))
}.toSeq
 .sortBy(_._1)
 .map(_._2)

This goes through the list, summing up values, and accumulating the result in a map, keyed by the second element of the tuple. Then convert the resulting map to a sequence of tuples, sort it by key, and then drop it, returning just a Seq of sums.

Upvotes: 1

RAGHHURAAMM
RAGHHURAAMM

Reputation: 1099

Given Lists:

val List_1 = List((2.0,0), (4.5,1), (1.2,1), (3.0,3), (4.4,1), (4.5,0), (1.7,0), (5.3,2), (2.0,3))
val List_2 = List(0,1,2,3)

Just put them in for comprehension with little changes in your code as shown here:

for(i<-List_2) yield List_1.filter(_._2==i).map(e=>e._1).sum

or

List_2.map(i=>List_1.filter(_._2==i).map(e=>e._1).sum)

and you are done.

In Scala REPL:

scala> for(i<-List_2) yield (List_1.filter(_._2==i).map(e=>e._1).sum)
res7: List[Double] = List(8.2, 10.100000000000001, 5.3, 5.0)
scala> List_2.map(i=>List_1.filter(_._2==i).map(e=>e._1).sum)
res10: List[Double] = List(8.2, 10.100000000000001, 5.3, 5.0)

Upvotes: 0

Related Questions