Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sum of sequence of Vectors in Scala

I have a sequence of Vectors of doubles: val vectors = Seq[Vector[Double]]

I'd like to sum all the vectors in the sequence, i.e. val total = vectors.sum

For example, if I have a sequence with two vectors [1,2] and [3,4], then the result should be [4,6]

However, the sum method of the Vector type requires an implicit Numeric.

What I have now is:

val total = vectors.reduce( (one,two) => one.zip(two).map(tuple => tuple._1 + tuple._2) )

I'm new to Scala, but I find this confusing and I assume that it's probably inefficient.

Is there a better way to do this?

like image 517
Bryan Glazer Avatar asked Sep 25 '22 19:09

Bryan Glazer


People also ask

How do you calculate sum in Scala?

Scala List sum() method with example. The sum() method is utilized to add all the elements of the stated list. Return Type: It returns the sum of all the elements of the list.

What is a SEQ in Scala?

Scala Seq is a trait to represent immutable sequences. This structure provides index based access and various utility methods to find elements, their occurences and subsequences. A Seq maintains the insertion order.

How do you add to a vector in Scala?

Adding elements to the vector: A single element can be added to the vector in Scala using :+ operator and multiple elements can be added in the vector using ++ operator.


2 Answers

This tail recursive function will work even if the Vectors have different lengths and can be applied to any numeric type:

@scala.annotation.tailrec
def recSum[T : Numeric](s : Iterable[Iterable[T]]) : List[T] = {
  val goodVecs = s.filterNot(_.isEmpty)

  if(goodVecs.isEmpty) 
    List.empty[T]
  else 
    goodVecs.map(_.head).sum :: recSum(goodVecs.map(_.tail))
}

Applying it to your example:

recSum(Seq(Vector(1.0,2.0), Vector(3.0,4.0,5.0))) //List(4.0,6.0,5.0)

recSum(Seq.empty[Vector[Double]]) // List()
like image 176
Ramón J Romero y Vigil Avatar answered Oct 11 '22 04:10

Ramón J Romero y Vigil


The approach you took in your original question is along the same lines I would do it. Since you raised a concern about efficiency, my answer includes the use of iterators, so that operations like zip and map will simply return a new iterator, rather than rebuilding an entire collection. I also adapted your approach to work for any non-zero number of input vectors.

Example input:

val vecs = Seq(   
  Vector(1,2,3,4,5),
  Vector(2,3,4,5,6),
  Vector(8,2,6,4,2),
  Vector(2,8,4,8,8) 
)

First step, transform the Seq[Vector] to a Seq[Iterator]

val iterators: Seq[Iterator[Int]] = vecs.map(_.iterator)

Now reduce that Seq into a single iterator. This is pretty similar to what you wrote in your original question:

val sumIterator = iterators.reduce[Iterator[Int]]{ (itrA, itrB) =>
  // combine 2 of the iterators into a sum of their individual parts
  // the resulting iterator will then be combined with the next iterator
  // so you end up with a single iterator of the total sum for each 'column'

  (itrA zip itrB) map { case (a, b) => a + b }
}

You can now use the sumIterator to find the sums of each 'column' in your 'matrix'.

sumIterator.toList
// List(13, 15, 17, 21, 21)
like image 32
Dylan Avatar answered Oct 11 '22 04:10

Dylan