Scala中矢量序列的总和

时间:2015-12-30 17:53:15

标签: scala scala-collections

我有一系列双打矢量:val vectors = Seq[Vector[Double]]

我希望对序列中的所有向量求和,即val total = vectors.sum

例如,如果我有一个包含两个向量[1,2][3,4]的序列,那么结果应为[4,6]

但是,sum类型的Vector方法需要隐式Numeric

我现在拥有的是:

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

我是Scala的新手,但我发现这令人困惑,我认为它可能效率低下。

有更好的方法吗?

3 个答案:

答案 0 :(得分:3)

即使向量具有不同的长度并且可以应用于任何数字类型,此尾递归函数也将起作用:

@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))
}

将它应用于您的示例:

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()

答案 1 :(得分:1)

您在原始问题中采用的方法与我所做的相同。由于您提出了对效率的关注,我的答案包括使用迭代器,因此像zipmap这样的操作将只返回一个新的迭代器,而不是重建整个集合。我还调整了你的方法来处理任何非零数量的输入向量。

示例输入:

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) 
)

第一步,将Seq [Vector]转换为Seq [Iterator]

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

现在reduceSeq放入单个迭代器中。这与您在原始问题中所写的内容非常相似:

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 }
}

您现在可以使用sumIterator查找每个'列的总和。在您的'矩阵'。

sumIterator.toList
// List(13, 15, 17, 21, 21)

答案 2 :(得分:0)

使用Vector减少内部sum,然后使用Seq减少外部sum

scala> val vectors: Seq[Vector[Double]] = List(Vector(.1,.2),Vector(.3,.4))
vectors: Seq[Vector[Double]] = List(Vector(0.1, 0.2), Vector(0.3, 0.4))

scala> vectors.map(_.sum).sum
res10 Double = 1.0