math.combinatorics的文档指出所有函数都返回惰性序列。
但是,如果我尝试使用大量数据运行subsets,
(last (combinatorics/subsets (range 20)))
;OutOfMemoryError Java heap space clojure.lang.RT.cons (RT.java:559)
我收到内存不足错误。
跑步
(last (range))
刻录CPU,但不会返回错误。
Clojure似乎没有像in this Stack Overflow question所解释的那样“坚持住”。
为什么会发生这种情况,以及如何在子集中使用更大的范围?
更新资料
如评论所示,它似乎可以在某些人的计算机上运行。所以我将发布我的系统配置
我运行Mac(10.8.3),并用Clojure安装了Homebrew(1.5.1)。
我的Java版本是:
% java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06-451-11M4406)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01-451, mixed mode)
我没有更改任何默认设置。我还通过删除
~/.m2
文件夹重新安装了所有依赖项。我的projects.clj。
我使用的命令是
% lein repl
nREPL server started on port 61774
REPL-y 0.1.10
Clojure 1.5.1
=> (require 'clojure.math.combinatorics)
nil
=> (last (clojure.math.combinatorics/subsets (range 20)))
OutOfMemoryError Java heap space clojure.lang.RT.cons (RT.java:570)
or
OutOfMemoryError Java heap space clojure.math.combinatorics/index-combinations/fn--1148/step--1164 (combinatorics.clj:64)
我在同事的笔记本电脑上测试了这个问题,他也遇到了同样的问题,但是他也在Mac上。
最佳答案
问题是subsets
使用mapcat
,并且mapcat
不够懒惰,因为它使用apply来实现并保存要串联的某些元素。请参见a very nice explanation here。在子集中使用该链接的lazier mapcat版本应可解决此问题:
(defn my-mapcat
[f coll]
(lazy-seq
(if (not-empty coll)
(concat
(f (first coll))
(my-mapcat f (rest coll))))))
(defn subsets
"All the subsets of items"
[items]
(my-mapcat (fn [n] (clojure.math.combinatorics/combinations items n))
(range (inc (count items)))))
(last (subsets (range 50))) ;; this will take hours to compute, good luck with it!