在Scala中计算向量序列之和

5
我有一系列双精度向量:val vectors = Seq[Vector[Double]] 我想要将序列中的所有向量相加,即:val total = vectors.sum 例如,如果我有一个包含两个向量[1,2][3,4]的序列,则结果应为[4,6] 然而,Vector类型的sum方法需要一个隐式的Numeric 现在我所拥有的是:
val total = vectors.reduce( (one,two) => one.zip(two).map(tuple => tuple._1 + tuple._2) )

我刚接触Scala,但是我感到困惑,而且我认为这可能效率低下。

有更好的方法吗?


你想要一个 Seq [Vector [Double]] 还是一个 Seq [(Double, Double)] - Michael Zajac
我只需要一个 Vector[Double]。如果我有一个包含两个向量 [1,2] 和 [3,4] 的序列,则我希望结果是 [4,6]。 - Bryan Glazer
1
如果有一个 Vector(1, 2, 3),你确定你需要的是数据类型 Vector 而不是 Tuple2 吗?它们并不相同。 - Michael Zajac
@BryanGlazer 使用元组来保证长度。 - Reactormonk
我认为你自己的解决方案比迄今为止给出的任何答案都要清晰明了 :) - Dima
显示剩余2条评论
3个回答

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

scala> Seq[Int]().head java.util.NoSuchElementException: head of empty list - Kevin Meredith
@KevinMeredith,我不理解你的评论。是什么输入值导致了这个异常? - Ramón J Romero y Vigil
我的错误在于没有详细说明。我的意思是不应该使用 Seq#head。请参阅http://www.cis.upenn.edu/~cis194/spring13/lectures/03-rec-poly.html#total-and-partial-functions。 - Kevin Meredith
1
@KevinMeredith 一般来说,我同意head是不安全的。但是,在这种情况下,由于filterNot的存在,我可以确保我的goodVecs Seq中的每个“Vector”至少有1个元素。因此,永远不会抛出NoSuchElementException异常。如果我将head应用于输入序列,则您的论点和相关文章将完全正确。 - Ramón J Romero y Vigil

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)

现在将Seq缩减为单个迭代器。这与您在原始问题中编写的内容非常相似。
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)

0

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接