Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add list of tuples of integers in Scala

I wish to add a list of tuples of integers i.e. given an input list of tuples of arity k, produce a tuple of arity k whose fields are sums of corresponding fields of the tuples in the list.

Input

List( (1,2,3), (2,3,-3), (1,1,1)) 

Output

(4, 6, 1)

I was trying to use foldLeft, but I am not able to get it to compile. Right now, I am using a for loop, but I was looking for a more concise solution.

like image 202
Parag Avatar asked Sep 16 '13 19:09

Parag


3 Answers

This can be done type safely and very concisely using shapeless,

scala> import shapeless._, syntax.std.tuple._
import shapeless._
import syntax.std.tuple._

scala> val l = List((1, 2, 3), (2, 3, -1), (1, 1, 1))
l: List[(Int, Int, Int)] = List((1,2,3), (2,3,-1), (1,1,1))

scala> l.map(_.toList).transpose.map(_.sum)
res0: List[Int] = List(4, 6, 3)

Notice that unlike solutions which rely on casts, this approach is type safe, and any type errors are detected at compile time rather than at runtime,

scala> val l = List((1, 2, 3), (2, "foo", -1), (1, 1, 1))
l: List[(Int, Any, Int)] = List((1,2,3), (2,foo,-1), (1,1,1))

scala> l.map(_.toList).transpose.map(_.sum)
<console>:15: error: could not find implicit value for parameter num: Numeric[Any]
              l.map(_.toList).transpose.map(_.sum)
                                          ^
like image 182
Miles Sabin Avatar answered Nov 15 '22 07:11

Miles Sabin


scala> val tuples = List( (1,2,3), (2,3,-3), (1,1,1))
tuples: List[(Int, Int, Int)] = List((1,2,3), (2,3,-3), (1,1,1))

scala> tuples.map(t => t.productIterator.toList.map(_.asInstanceOf[Int])).transpose.map(_.sum)
res0: List[Int] = List(4, 6, 1)

Type information is lost when calling productIterator on Tuple3 so you have to convert from Any back to an Int.

If the tuples are always going to contain the same type I would suggest using another collection such as List. The Tuple is better suited for disparate types. When you have the same types and don't lose the type information by using productIterator the solution is more elegant.

scala> val tuples = List(List(1,2,3), List(2,3,-3), List(1,1,1))
tuples: List[List[Int]] = List(List(1, 2, 3), List(2, 3, -3), List(1, 1, 1))

scala> tuples.transpose.map(_.sum)
res1: List[Int] = List(4, 6, 1)
like image 22
Brian Avatar answered Nov 15 '22 06:11

Brian


scala> val list = List( (1,2,3), (2,3,-3), (1,1,1))
list: List[(Int, Int, Int)] = List((1,2,3), (2,3,-3), (1,1,1))

scala> list.foldRight( (0, 0, 0) ){ case ((a, b, c), (a1, b1, c1)) => (a + a1, b + b1, c + c1) }
res0: (Int, Int, Int) = (4,6,1)
like image 21
Nikita Volkov Avatar answered Nov 15 '22 07:11

Nikita Volkov