Kotlin 函数式向量点积
Kotlin Functional Vector Dot Product
我有一个 Kotlin Vector class,它包含一个函数来计算两个 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
}
}
我想用函数式的方式表达两个向量的点积。折叠会初始化,但我不知道如何让它与两个数组一起工作。
有人有什么建议吗?
您可以使用转换函数压缩它们,然后求和:
return values.asSequence().zip(v.values.asSequence()) { a, b -> a * b }.sum()
或
return values.zip(v.values) { a, b -> a * b }.sum()
或
return values.zip(v.values, Double::times).sum()
我会 zip
the the two arrays, and then use sumByDouble
:
fun dot(v: Vector): Double = values
.apply { require(size == v.values.size) }
.zip(v.values)
.sumByDouble { (a, b) -> a * b }
旁注:如果您使用的是 JVM,则可以 。前者在 JVM 上将表示为一个 double[]
,而不是一个装箱的 Double
数组。
接受的答案是准确的,但效率不高:将数组压缩在一起会分配一个新列表,复制两个源数组,并为每个数据元素生成一个 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
}
这纯粹是功能性的,因为它没有副作用,并且总是 returns 给定相同的输入得到相同的结果。您的消费者永远不会知道您的 for
循环秘密。
你 可以 使用 foldIndexed
来完成,但是,对于那种光滑、实用的 Kotlin 样式:
infix fun DoubleArray.dot(other: DoubleArray) =
foldIndexed(0.0) { i, acc, cur -> acc + cur * other[i] }
虽然我觉得这有点难读(所有那些 cur
s 和 acc
s,加上一个奇怪的浮动 0.0
);在幕后,foldIndexed
只是在使用 for
循环。
我有一个 Kotlin Vector class,它包含一个函数来计算两个 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
}
}
我想用函数式的方式表达两个向量的点积。折叠会初始化,但我不知道如何让它与两个数组一起工作。
有人有什么建议吗?
您可以使用转换函数压缩它们,然后求和:
return values.asSequence().zip(v.values.asSequence()) { a, b -> a * b }.sum()
或
return values.zip(v.values) { a, b -> a * b }.sum()
或
return values.zip(v.values, Double::times).sum()
我会 zip
the the two arrays, and then use sumByDouble
:
fun dot(v: Vector): Double = values
.apply { require(size == v.values.size) }
.zip(v.values)
.sumByDouble { (a, b) -> a * b }
旁注:如果您使用的是 JVM,则可以 double[]
,而不是一个装箱的 Double
数组。
接受的答案是准确的,但效率不高:将数组压缩在一起会分配一个新列表,复制两个源数组,并为每个数据元素生成一个 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
}
这纯粹是功能性的,因为它没有副作用,并且总是 returns 给定相同的输入得到相同的结果。您的消费者永远不会知道您的 for
循环秘密。
你 可以 使用 foldIndexed
来完成,但是,对于那种光滑、实用的 Kotlin 样式:
infix fun DoubleArray.dot(other: DoubleArray) =
foldIndexed(0.0) { i, acc, cur -> acc + cur * other[i] }
虽然我觉得这有点难读(所有那些 cur
s 和 acc
s,加上一个奇怪的浮动 0.0
);在幕后,foldIndexed
只是在使用 for
循环。