所以我再次拿起 Project Euler 来玩一下 Kotlin。对于那些不知道 Project Euler 的人来说,这是一个提供从平庸到相当困难的编程练习的网站。
无论如何,第一个问题是:
如果我们列出所有 10 以下且是 3 或 5 的倍数的自然数,我们会得到 3、5、6 和 9。这些倍数的总和是 23。
求 1000 以下的所有 3 或 5 的倍数之和。
我按顺序和功能性地解决了这个问题,因为我想看看它们如何比较:
class ProjectEuler1 {
companion object {
fun sequential(): Int {
var sum = 0
for (i in 1..999)
if (i % 3 == 0 || i % 5 == 0)
sum += i
return sum
}
fun functional(): Int = (1..999).filter { it % 3 == 0 || it % 5 == 0 } .sum()
fun benchmark() {
var solSequential = -1
val tSequential = measureExactTimeMillis { solSequential = sequential() }
var solFunctional = -1
val tFunctional = measureExactTimeMillis { solFunctional = functional() }
println("""
+---
|${this::class.java.canonicalName.replace(".Companion", "")}
+---
|Sequential solution: $solSequential
|Sequential running time: ${tSequential.round(6)} ms
+---
|Functional solution: $solFunctional
|Functional running time: ${tFunctional.round(6)} ms
+---
""".trimIndent())
}
}
}
measureExactTimeMillis
只是 measureNanoTime
除以 1_000_000
返回 Double
。
无论如何,运行几次后,输出总是或多或少是这样的:
+---
|ProjectEuler1
+---
|Sequential solution: 233168
|Sequential running time: 0.6097 ms
+---
|Functional solution: 233168
|Functional running time: 33.3555 ms
+---
顺序版本(遗憾的是更加冗长)比简单的功能实现快 50-100 倍。
这是什么原因呢?难道性能不应该至少具有可比性(而不是相差几个数量级)吗?我是否错过了一些应该做的事情来优化功能实现?
listOf、setOf 和 mapOf 应分别返回持久向量、持久哈希集和持久哈希映射。
另外应该是一个持久链表。
Scala 就是这样做的,Clojure 也是如此,它采用了 Scala 的概念。