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?
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.
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.
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.
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()
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With