clojure - 非线性减速在 Clojure 中创建惰性序列

标签 clojure lazy-sequences

我实现了一个函数,该函数将给定输入集合的 n-gram 作为惰性序列返回。

(defn gen-ngrams
  [n coll]
  (if (>= (count coll) n)
    (lazy-seq (cons (take n coll) (gen-ngrams n (rest coll))))))

当我使用更大的输入集合调用此函数时,我希望看到执行时间线性增加。然而,我观察到的时间比那更糟:

user> (time (count (gen-ngrams 3 (take 1000 corpus))))
"Elapsed time: 59.426 msecs"
998
user> (time (count (gen-ngrams 3 (take 10000 corpus))))
"Elapsed time: 5863.971 msecs"
9998
user> (time (count (gen-ngrams 3 (take 20000 corpus))))
"Elapsed time: 23584.226 msecs"
19998
user> (time (count (gen-ngrams 3 (take 30000 corpus))))
"Elapsed time: 54905.999 msecs"
29998
user> (time (count (gen-ngrams 3 (take 40000 corpus))))
"Elapsed time: 100978.962 msecs"
39998

corpus 是字符串标记的 Cons

是什么导致了这种行为,我该如何提高性能?

最佳答案

我认为您的问题与“(count coll)”有关,它会在每次调用 ngrams 时迭代 coll。

解决方案是使用内置分区函数:

user=> (time (count (gen-ngrams 3 (take 20000 corpus))))
"Elapsed time: 6212.894932 msecs"
19998
user=> (time (count (partition 3 1 (take 20000 corpus))))
"Elapsed time: 12.57996 msecs"
19998

如果对实现感到好奇,请查看分区源代码 http://clojuredocs.org/clojure_core/clojure.core/partition

关于clojure - 非线性减速在 Clojure 中创建惰性序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10565874/

相关文章:

clojure - 如何正确使用LazySeq

clojure - 在clojure中懒惰地构建集合

Clojure从字符串中删除非数字

Clojure:查找向量向量中的最小值

Kotlin 的 Iterable 和 Sequence 看起来完全一样。为什么需要两种类型?

clojure - 延迟分区

Clojure:从输入流创建字节 block 的惰性序列

class - Clojure:为现有的 java 类实现 Seqable

java - 在 ClassLoader 上调用 `defineClass` 会导致 "No matching method found"

sml - 自然数的通用序列