Clojure Lazy Sequences:Kotlin中的等价物

时间:2018-06-07 19:10:01

标签: clojure kotlin lazy-evaluation sequences lazy-sequences

Clojure为(无限)序列中的延迟评估值提供了方法。这样,只有在实际消耗时才会计算值。

一个重复元素的无限序列的一个例子:

(take 3 (repeat "Hello StackOverflow")) 
//=> ("Hello StackOverflow" "Hello StackOverflow" "Hello StackOverflow")

使用take有助于仅消耗我们想要的序列中的任意数量的元素。没有它,OutOfMemoryError会很快杀死这个过程。

无限序列的另一个例子如下:

(take 5 (iterate inc 1)) 
//(1 2 3 4 5)

或提供阶乘函数的更高级序列:

((defn factorial [n]
   (apply * (take n (iterate inc 1)))) 5)

Kotlin是否提供类似的序列?它们看起来像什么?

我自己回答了这个问题,以便记录这里的知识。根据{{​​3}}

,这很好

1 个答案:

答案 0 :(得分:5)

在Kotlin中,我们也可以使用Sequences来进行惰性评估。为了创建序列,我们可以使用generateSequence(提供或不提供seed

fun <T : Any> generateSequence(
    seed: T?,
    nextFunction: (T) -> T?
): Sequence<T> (source)
     

返回由起始值seed和函数nextFunction定义的序列,该函数被调用以根据每次迭代的前一个值计算下一个值。

以下将展示一些比较Clojure与Kotlin序列的实例。

1。来自一个静态值的无限序列的简单take

<强> Clojure的

(take 3 (repeat "Hello StackOverflow")) 

<强>科特林

generateSequence { "Hello StackOverflow" }.take(3).toList()

这些非常相似。在Clojure中,我们可以使用repeat,而在Kotlin中,它只是generateSequence,其静态值将永远产生。在这两种情况下,都使用take来定义我们想要计算的元素数量。

注意:在Kotlin中,我们将生成的序列转换为toList()

的列表

2。来自无限动态值序列的简单take

<强> Clojure的

(take 5 (iterate inc 1))

<强>科特林

generateSequence(1) { it.inc() }.take(5).toList()

这个例子有点不同,因为序列无限地产生前一个值的增量。可以使用种子(此处为:generateSequence)和1(增加前一个值)来调用Kotlin nextFunction

3。循环重复列表中的值

<强> Clojure的

(take 5 (drop 2 (cycle [:first :second :third ])))
// (:third :first :second :third :first)

<强>科特林

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)))) 

我们从序列中取n个值,得到一个从1开始的递增数,并在apply的帮助下累积它们。

<强>科特林

fun factorial(n: Int) = generateSequence(1) { it.inc() }.take(n).fold(1) { v1, v2 ->
    v1 * v2
}

Kotlin提供fold,让我们轻松积累价值。