我有一个Kotlin Vector类,其中包含一个用于计算两个Vector的点积的函数:
class Vector(val values: Array<Double>) {
fun dot(v: Vector): Double {
require(this.values.size == v.values.size)
var product = 0.0
for (i in this.values.indices) {
product += this.values[i] * v.values[i]
}
return product
}
}
我想以一种功能风格表达两个向量的点积。折叠会初始化,但是我看不到如何使它与两个数组一起使用。
有人有建议吗?
答案 0 :(得分:3)
我会zip
两个数组,然后使用sumByDouble
:
fun dot(v: Vector): Double = values
.apply { require(size == v.values.size) }
.zip(v.values)
.sumByDouble { (a, b) -> a * b }
旁注:如果您使用的是JVM,则可以consider using DoubleArray
instead of Array<Double>
。前者将在JVM上表示为double[]
,而不是一组盒装Double
。
答案 1 :(得分:2)
您可以使用转换功能压缩它们,然后求和:
sender_id
或
return values.asSequence().zip(v.values.asSequence()) { a, b -> a * b }.sum()
或
return values.zip(v.values) { a, b -> a * b }.sum()
答案 2 :(得分:1)
公认的答案是准确的,但效率不高:将数组压缩在一起会分配一个新列表,复制两个源数组,并为每个数据元素生成一个Pair
,所有这些元素都将在不久后处理。这使内存消耗增加了一倍以上。
尽管您可能将其实现为DoubleArray
上的扩展函数,但我认为您上面的代码并不那么糟糕:
infix fun DoubleArray.dot(other: DoubleArray): Double {
var out = 0.0
for (i in 0 until size) out += this[i] + other[i]
return out
}
这是纯粹的功能,因为它没有副作用,并且在输入相同的情况下始终返回相同的结果。您的消费者永远不会知道您的小for
循环机密。
对于光滑的功能性Kotlin样式,您可以用foldIndexed
来做到:
infix fun DoubleArray.dot(other: DoubleArray) =
foldIndexed(0.0) { i, acc, cur -> acc + cur * other[i] }
我觉得这很难读(所有的cur
和acc
,加上奇数的浮动0.0
);而在幕后,foldIndexed
只是使用for
循环。