说我有一个列表(abcde),我试图找出一个“懒惰”和Clojure惯用的方法来生成每个项目的列表或seq与其他项目,如((ab)(ac )(ad)(ae)(bc)(bd)(be)(cd)(ce)(de))。
Clojure's for似乎不允许这样,它只生成一个项目,因为它通过列表并且不允许访问子列表。到目前为止,我最接近的是将原始列表转换为向量,并使用for语句迭代向量计数并获取索引项,
(对于[i(范围向量计数)j(范围向量计数)] ...
但我希望有更好的方法。
答案 0 :(得分:3)
你想要组合。有一个函数可以在clojure-contrib中为你提供一组懒惰的组合right here。
user> (combinations [:a :b :c :d :e] 2)
((:a :b) (:a :c) (:a :d) (:a :e) (:b :c) (:b :d) (:b :e) (:c :d) (:c :e) (:d :e))
(不幸的是,包含该文件的整体clojure-contrib repo已被弃用,支持将contrib分成更小的单独repos,而clojure.contrib.combinatorics
似乎尚未进行过渡,因此没有简单的方法目前要安装该库,但如果没有别的话,你可以从github获取代码。)
答案 1 :(得分:3)
FWIW,我试着写这个而不用看contrib中的代码。我认为我的代码更容易理解,而且在我简单的基准测试中,它的速度提高了两倍多。它可以在https://gist.github.com/1042047获得,并在下面转载以方便:
(defn combinations [n coll]
(if (= 1 n)
(map list coll)
(lazy-seq
(when-let [[head & tail] (seq coll)]
(concat (for [x (combinations (dec n) tail)]
(cons head x))
(combinations n tail))))))
user> (require '[clojure.contrib.combinatorics :as combine])
nil
user> (time (last (user/combinations 4 (range 100))))
"Elapsed time: 4379.959957 msecs"
(96 97 98 99)
user> (time (last (combine/combinations (range 100) 4)))
"Elapsed time: 10913.170605 msecs"
(96 97 98 99)
我非常喜欢[n coll]参数顺序,而不是[coll n] - clojure喜欢最后的“重要”参数,特别是对于处理seqs的函数:这主要是为了便于与{{1在(->>)
等场景中。
答案 2 :(得分:1)
为什么在for循环中使用范围和索引?
(let [myseq (list :a :b :c :d)]
(for [a myseq b myseq] (list a b)))
作品。