5

IndexedSeq[Double]在设计特定领域的数值计算库时寻找要使用的正确数据类型(例如)。对于这个问题,我将范围限制为使用Double. 该库将定义一个数字函数,这些函数通常应用于一维数组中的每个元素。

注意事项:

  • 首选不可变数据类型,例如VectorIndexedSeq
  • 想要最小化数据转换
  • 在空间和时间上合理高效
  • 对使用图书馆的其他人友好
  • 优雅干净的 API

我应该使用集合层次结构更高的东西,例如Seq

还是只定义单元素函数并将映射/迭代留给最终用户更好?

这似乎效率较低(因为每组调用一次可以完成一些计算),但同时是一个更灵活的 API,因为它适用于任何类型的集合。

有什么建议吗?

4

2 回答 2

11

如果您的计算要执行任何远程计算密集型的操作,请使用Arrayraw 或包装在您自己的类中。您可以提供与集合兼容的包装器,但将其作为显式包装器仅用于互操作性。除此以外的所有东西Array都是通用的,因此是盒装的,因此相对缓慢和笨重。

如果您不使用Array,人们将被迫放弃您拥有的任何东西,而只Array在性能很重要时使用。也许没关系;也许您希望计算在那里是为了方便而不是为了提高效率。在这种情况下,我建议使用IndexedSeqfor 接口,假设您想让人们知道索引不是非常慢(例如 is not List),并Vector在后台使用。对于大多数省力的操作(例如乘法),您将使用大约 4 倍的内存Array[Double],并且速度会慢 3-10 倍。

例如,这个:

val u = v.map(1.0 / _)   //  v is Vector[Double]

比这慢大约三倍:

val u = new Array[Double](v.length)
var j = 0
while (j<u.length) {
  u(j) = 1.0/v(j)      // v is Array[Double]
  j += 1
}

如果你使用map方法 on Array,它和方法一样慢Vector[Double];上的操作Array是通用的,因此被装箱。(这就是大部分惩罚的来源。)

于 2012-12-05T16:24:17.460 回答
3

当我处理数值时,我一直在使用向量,因为它提供了非常有效的随机访问以及附加/前置。

另请注意,不可变索引序列的当前默认集合是 Vector,因此如果您编写类似 的代码for (i <- 0 until n) yield {...},它会返回,IndexedSeq[...]但运行时类型是 Vector。因此,始终使用向量可能是一个好主意,因为一些将两个序列作为输入的二元运算符可能会受益于两个参数具有相同实现类型的事实。(现在情况并非如此,但有人指出向量连接可能在 log(N) 时间内,而不是当前的线性时间,因为第二个参数被简单地视为一般序列。)

尽管如此,我相信Seq[Double]应该已经提供了你需要的大部分功能接口。而且由于 Range 的映射结果不会Vector直接产生,所以我通常将Seq[Double]参数类型作为我的输入,以便它具有一些通用性。我希望在底层实现中优化效率。

希望有帮助。

于 2012-12-05T15:31:10.590 回答