Scala 中向量序列的总和
Sum of sequence of Vectors in Scala
我有一个双精度向量序列: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 的新手,但我觉得这很混乱,我认为它可能效率低下。
有更好的方法吗?
即使 Vectors 具有不同的长度并且可以应用于任何数字类型,这个尾递归函数仍然有效:
@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()
您在原始问题中采用的方法与我采用的方法相同。由于您提出了对效率的担忧,我的回答包括迭代器的使用,因此 zip
和 map
之类的操作只会 return 一个新的迭代器,而不是重建整个集合。我还调整了您的方法以适用于任何 non-zero 个输入向量。
示例输入:
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)
现在 reduce
那个 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
计算 'matrix' 中每个 'column' 的总和。
sumIterator.toList
// List(13, 15, 17, 21, 21)
用sum
减少内部Vector
s,然后用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
我有一个双精度向量序列: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 的新手,但我觉得这很混乱,我认为它可能效率低下。
有更好的方法吗?
即使 Vectors 具有不同的长度并且可以应用于任何数字类型,这个尾递归函数仍然有效:
@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()
您在原始问题中采用的方法与我采用的方法相同。由于您提出了对效率的担忧,我的回答包括迭代器的使用,因此 zip
和 map
之类的操作只会 return 一个新的迭代器,而不是重建整个集合。我还调整了您的方法以适用于任何 non-zero 个输入向量。
示例输入:
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)
现在 reduce
那个 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
计算 'matrix' 中每个 'column' 的总和。
sumIterator.toList
// List(13, 15, 17, 21, 21)
用sum
减少内部Vector
s,然后用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