Clojure list(seq)遍历将项目与其他项目进行比较

时间:2011-06-22 23:02:26

标签: clojure

说我有一个列表(abcde),我试图找出一个“懒惰”和Clojure惯用的方法来生成每个项目的列表或seq与其他项目,如((ab)(ac )(ad)(ae)(bc)(bd)(be)(cd)(ce)(de))。

Clojure's for似乎不允许这样,它只生成一个项目,因为它通过列表并且不允许访问子列表。到目前为止,我最接近的是将原始列表转换为向量,并使用for语句迭代向量计数并获取索引项,

  

(对于[i(范围向量计数)j(范围向量计数)]   ...

但我希望有更好的方法。

3 个答案:

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

作品。