嵌套增加的foreach循环

时间:2014-05-16 22:59:13

标签: foreach clojure nested-loops

获得类似内容的惯用方法是什么?

((fn [coll] (function-body)) [:a :b :c :d]) 
-> [[:a :b][:a :c][:a :d][:b :c][:b :d][:c :d]]

我只能这样做。

#(for [i (range (count %))
       j (range (inc i) (count %))]
   [(nth % i) (nth % j)])

但这很丑陋,而且收藏速度很慢。我想避免循环/重复

5 个答案:

答案 0 :(得分:3)

明确使用递归...

(defn pairs [coll]
  (if-let [[x & xs] (seq coll)]
    (lazy-cat (map #(vector x %) xs) (pairs xs))))

例如,

(pairs [:a :b :c :d])
; ([:a :b] [:a :c] [:a :d] [:b :c] [:b :d] [:c :d])

这是一个懒惰的序列。如果需要,您可以使用vec将其倒入向量中:我认为最好留给客户做出决定。

答案 1 :(得分:0)

这是一个懒惰的解决方案。

user> (def data [:a :b :c :d]) 
#'user/data
user> (defn loopy [data] 
         (lazy-seq (if (seq data) 
                       (cons (map #(vector (first data) %) (rest data)) 
                             (loopy (rest data))) 
                        nil))) 
#'user/loopy   

user> (apply concat (loopy data)) 
([:a :b] [:a :c] [:a :d] [:b :c] [:b :d] [:c :d])

这会产生一个惰性序列,其中每个元素都是一个懒惰的序列,它将当前元素的向量创建到一个向量中,其中包含其余每个元素。当此段通过调用(apply concat )为空时,会延迟生成下一个段。

答案 2 :(得分:0)

我找到了解决问题的丑陋管道。我发现它不太优雅,但我还没有能够美化它。

(->> [:a :b :c :d] 
     (iterate rest) 
     (take-while not-empty) 
     (mapcat (fn [[f & r]] (map #(vector f %) r)))
     vec)

在给定列表[:a :b :c :d]时,让我们分析mapcat中的函数。它使用第一个元素:a计算所有向量,并从[:b :c :d], that is([:a:b] [:a:c] [:a:d])`中获取第二个元素连续元素。

管道的第一部分构造了原始向量([:a :b :c :d](:b :c :d)(:c :d)(:d) () () () ...)的所有休止符的序列,该序列在第一个空的休息时停止。

然后mapcat在前面描述的组合函数中插入此列表,最后的vec将序列转换为向量。

通过引入一些辅助功能,这可以更具可读性:

(defn rests [coll] 
  (take-while not-empty (iterate rest coll)))

(defn pairfirst [[f & r]] 
  (map #(vector f %) r))

(defn pairs [coll]
  (mapcat pairfirst (rests coll)))

答案 3 :(得分:0)

这与Juan Manuel的答案一致,我发现在最后一部分使用列表理解更具可读性。匿名函数为[(first s) x]

中的所有元素生成对(rest s). l
(defn pairs [xs]
   (->> xs
       (iterate rest)
       (take-while seq)
       (mapcat #(for [x (rest %)]
                  [(first %) x]))))

答案 4 :(得分:0)

for is already lazyfilter is too。因此,如果元素具有自然顺序,执行此操作的一种方法是生成笛卡尔乘积,然后按排序顺序进行过滤。

(defn pairs [c]
  (->> (for [x c, y c] [x y])
       (filter #(apply <= %))))

(def c (range 0 1e7))

(time (nth (pairs c) 0))    ;; ~ 0.07 ms
(time (nth (pairs c) 1e4))  ;; ~ 6 ms
(time (nth (pairs c) 1e7))  ;; ~ 2600 ms

我认为您使用nth可能会减慢集合迭代的速度:

(def pairs2
  #(for [i (range (count %))
         j (range (inc i) (count %))]
     [(nth % i) (nth % j)]))

(def c (range 0 1e7))

(time (nth (pairs2 c) 0))    ;; ~ 960 ms
(time (nth (pairs2 c) 1e4))  ;; ~ 1514 ms
(time (nth (pairs2 c) 1e7))  ;; ~ ¯\_(ツ)_/¯