Clojure 惰性序列:Kotlin 中的等价物
Clojure Lazy Sequences: Equivalents in Kotlin
Clojure 提供了对(无限)序列中的值进行惰性求值 的方法。这样,只有在实际使用时才会计算值。
一个重复元素的无限序列示例:
(take 3 (repeat "Hello Whosebug"))
//=> ("Hello Whosebug" "Hello Whosebug" "Hello Whosebug")
使用take
有助于只消耗我们想要的序列中尽可能多的元素。没有它,OutOfMemoryError
会很快终止进程。
无限序列的另一个例子如下:
(take 5 (iterate inc 1))
//(1 2 3 4 5)
或提供阶乘函数的更高级序列:
((defn factorial [n]
(apply * (take n (iterate inc 1)))) 5)
Kotlin 是否提供类似的序列?他们长什么样?
为了记录这里的知识,我自己回答了这个问题。根据 Can I answer my own question?
这很好
在 Kotlin 中,我们还可以使用 Sequences, too. In order to create a sequence, we may use generateSequence
进行惰性求值(提供或不提供 seed
。
fun <T : Any> generateSequence(
seed: T?,
nextFunction: (T) -> T?
): Sequence<T> (source)
Returns a sequence defined by the starting value seed
and the function nextFunction
, which is invoked to calculate the next value based on the previous one on each iteration.
下面将展示一些比较 Clojure 和 Kotlin 序列的例子。
1。来自一个静态值
的无限序列的简单 take
Clojure
(take 3 (repeat "Hello Whosebug"))
Kotlin
generateSequence { "Hello Whosebug" }.take(3).toList()
这些非常相似。在 Clojure 中,我们可以使用 repeat
而在 Kotlin 中,它只是 generateSequence
和一个将永远产生的静态值。在这两种情况下,都使用 take
来定义我们要计算的元素数量。
注意:在 Kotlin 中,我们将生成的序列转换为具有 toList()
的列表
2。来自动态值
的无限序列的简单 take
Clojure
(take 5 (iterate inc 1))
Kotlin
generateSequence(1) { it.inc() }.take(5).toList()
这个例子有点不同,因为序列无限地产生前一个值的增量。 Kotlin generateSequence
可以用种子(此处:1
)和 nextFunction
(递增先前的值)调用。
3。循环重复列表中的值
Clojure
(take 5 (drop 2 (cycle [:first :second :third ])))
// (:third :first :second :third :first)
Kotlin
listOf("first", "second", "third").let { elements ->
generateSequence(0) {
(it + 1) % elements.size
}.map(elements::get)
}.drop(2).take(5).toList()
在这个例子中,我们循环重复列表的值,删除前两个元素,然后取 5。这在 Kotlin 中恰好非常冗长,因为重复列表中的元素并不简单。为了修复它,一个简单的扩展函数使相关代码更具可读性:
fun <T> List<T>.cyclicSequence() = generateSequence(0) {
(it + 1) % this.size
}.map(::get)
listOf("first", "second", "third").cyclicSequence().drop(2).take(5).toList()
4。阶乘
最后但同样重要的是,让我们看看如何使用 Kotlin 序列解决阶乘问题。首先,让我们回顾一下Clojure版本:
Clojure
(defn factorial [n]
(apply * (take n (iterate inc 1))))
我们从产生从 1 开始的递增数字的序列中取 n 个值,并在 apply
的帮助下累加它们。
Kotlin
fun factorial(n: Int) = generateSequence(1) { it.inc() }.take(n).fold(1) { v1, v2 ->
v1 * v2
}
Kotlin 提供 fold
让我们轻松地积累价值。
Clojure 提供了对(无限)序列中的值进行惰性求值 的方法。这样,只有在实际使用时才会计算值。
一个重复元素的无限序列示例:
(take 3 (repeat "Hello Whosebug"))
//=> ("Hello Whosebug" "Hello Whosebug" "Hello Whosebug")
使用take
有助于只消耗我们想要的序列中尽可能多的元素。没有它,OutOfMemoryError
会很快终止进程。
无限序列的另一个例子如下:
(take 5 (iterate inc 1))
//(1 2 3 4 5)
或提供阶乘函数的更高级序列:
((defn factorial [n]
(apply * (take n (iterate inc 1)))) 5)
Kotlin 是否提供类似的序列?他们长什么样?
为了记录这里的知识,我自己回答了这个问题。根据 Can I answer my own question?
这很好在 Kotlin 中,我们还可以使用 Sequences, too. In order to create a sequence, we may use generateSequence
进行惰性求值(提供或不提供 seed
。
fun <T : Any> generateSequence( seed: T?, nextFunction: (T) -> T? ): Sequence<T> (source)
Returns a sequence defined by the starting value
seed
and the functionnextFunction
, which is invoked to calculate the next value based on the previous one on each iteration.
下面将展示一些比较 Clojure 和 Kotlin 序列的例子。
1。来自一个静态值
的无限序列的简单take
Clojure
(take 3 (repeat "Hello Whosebug"))
Kotlin
generateSequence { "Hello Whosebug" }.take(3).toList()
这些非常相似。在 Clojure 中,我们可以使用 repeat
而在 Kotlin 中,它只是 generateSequence
和一个将永远产生的静态值。在这两种情况下,都使用 take
来定义我们要计算的元素数量。
注意:在 Kotlin 中,我们将生成的序列转换为具有 toList()
2。来自动态值
的无限序列的简单take
Clojure
(take 5 (iterate inc 1))
Kotlin
generateSequence(1) { it.inc() }.take(5).toList()
这个例子有点不同,因为序列无限地产生前一个值的增量。 Kotlin generateSequence
可以用种子(此处:1
)和 nextFunction
(递增先前的值)调用。
3。循环重复列表中的值
Clojure
(take 5 (drop 2 (cycle [:first :second :third ])))
// (:third :first :second :third :first)
Kotlin
listOf("first", "second", "third").let { elements ->
generateSequence(0) {
(it + 1) % elements.size
}.map(elements::get)
}.drop(2).take(5).toList()
在这个例子中,我们循环重复列表的值,删除前两个元素,然后取 5。这在 Kotlin 中恰好非常冗长,因为重复列表中的元素并不简单。为了修复它,一个简单的扩展函数使相关代码更具可读性:
fun <T> List<T>.cyclicSequence() = generateSequence(0) {
(it + 1) % this.size
}.map(::get)
listOf("first", "second", "third").cyclicSequence().drop(2).take(5).toList()
4。阶乘
最后但同样重要的是,让我们看看如何使用 Kotlin 序列解决阶乘问题。首先,让我们回顾一下Clojure版本:
Clojure
(defn factorial [n]
(apply * (take n (iterate inc 1))))
我们从产生从 1 开始的递增数字的序列中取 n 个值,并在 apply
的帮助下累加它们。
Kotlin
fun factorial(n: Int) = generateSequence(1) { it.inc() }.take(n).fold(1) { v1, v2 ->
v1 * v2
}
Kotlin 提供 fold
让我们轻松地积累价值。