[英]Idiomatic way to iterate through all pairs of a collection in Clojure
Given a collection I want to iterate through all pairs in a collection. 给定一个集合,我想迭代集合中的所有对。 Example
例
(all-pairs seq)
(all-pairs '(a b c d)) => ([a b] [a c] [a d] [b c] [b d] [c d]))
Here is my idea 这是我的想法
(defn all-pairs [coll]
(for [ [idx elmt] (indexed coll)
other-elmt (subvec coll (inc idx))]
(vector elmt other-elm)))
But it doesn't feel idiomatic 但它并不像惯用语
How about: 怎么样:
(use 'clojure.contrib.combinatorics)
(vec (map vec (combinations '(a b c d) 2)))
Lazy, and relatively fast. 懒惰,而且比较快。
(defn all-pairs [coll]
(when-let [s (next coll)]
(lazy-cat (for [y s] [(first coll) y])
(all-pairs s))))
(defn all-pairs [coll]
(let [x (first coll) xs (next coll)]
(when xs
(lazy-cat
(map (fn [y] [x y]) xs)
(all-pairs xs)))))
(all-pairs [1 2 3 4])
;; => ([1 2] [1 3] [1 4] [2 3] [2 4] [3 4])
(all-pairs [1 2 3 4])
;; => ([1 2] [1 3] [1 4] [2 3] [2 4] [3 4])
;; => ([1 2] [1 3] [1 4] [2 3] [2 4] [3 4])
(all-pairs '(abcd))
;; => ([ab] [ac] [ad] [bc] [bd] [cd])
(all-pairs '(abcd))
;; => ([ab] [ac] [ad] [bc] [bd] [cd])
;; => ([ab] [ac] [ad] [bc] [bd] [cd])
(defn all-pairs [coll]
(loop [[x & xs] coll
result []]
(if (nil? xs)
result
(recur xs (concat result (map #(vector x %) xs))))))
May I suggest: 我可以建议:
(defn all-pairs [sq] (for [i sq j sq] [i j]))
EDIT: Clearly I misread the question; 编辑:显然我误解了这个问题; since you only want distinct unduplicated pairs, we can still use this approach if a natural ordering exists on whatever domain you're calling this function on.
因为你只需要不同的非重复对,所以如果在你调用这个函数的任何域上存在自然排序,我们仍然可以使用这种方法。
(defn all-pairs [sq] (filter #(< (first %) (second %)) (for [i sq j sq] [i j])))
EDIT 2 编辑2
Also: 也:
(defn all-pairs [sq]
(partition 2 (flatten (map (fn [sqi] (map #(vector %1 %2) sq sqi))
(take-while not-empty (iterate rest (rest sq)))))))
If you want to write your own combinations
function in "academic style," you can try 如果你想用“学院风格”编写自己的
combinations
功能,你可以试试
(defn comb [xs m]
(cond
(= m 0) (list ())
(empty? (seq xs)) ()
:else (let [x (first xs)
xs (rest xs)]
(concat
(map #(cons x %) (comb xs (- m 1)))
(comb xs m)))))
and then apply it to your problem as follows 然后将其应用于您的问题,如下所示
(map vec (comb '(a b c d) 2))
([ab] [ac] [ad] [bc] [bd] [cd])
What about this? 那这个呢?
(defn seq->pairs
[s]
(loop [res [] s s]
(let [[head next] (split-at 2 s)
res (conj res head)]
(if (empty? next) res (recur res next)))))
Just another possible solution: 另一种可能的解决方案
(defn all-pairs
[c]
(mapcat #(drop % %2)
(range 1 (count c))
(partition (count c) (for [a c b c] [a b]))))
(all-pairs '(a b c d)) => ([a b] [a c] [a d] [b c] [b d] [c d]))
(all-pairs [5 4 3 2 1]) => ([5 4] [5 3] [5 2] [5 1] [4 3] [4 2] [4 1] [3 2] [3 1] [2 1])
(all-pairs "pairs") => ([\p \a] [\p \i] [\p \r] [\p \s] [\a \i] [\a \r] [\a \s] [\i \r] [\i \s] [\r \s])
A simple recursive version that should do what you want: 一个简单的递归版本,应该做你想要的:
(defn all-pairs [coll]
(let [x (first coll)
xs (rest coll)]
(if (empty? xs)
nil
(concat
(map (fn [y] [x y]) xs)
(all-pairs xs)))))
Not the fastest solution, but: 不是最快的解决方案,但是:
; handy helper function
(defn tails [v]
"Given a sequence ( a b c ), returns all tails: ( a b c ) ( b c ) ( c )"
(when (seq v)
(lazy-cat (list v) (tails (rest v)))))
(defn pair* [v]
"Match the first item in the list with all others in pairs."
(when (> (count v) 1)
(for [y v] [(first v) y])))
(defn all-pairs [v]
(apply concat (map pair* (tails v))))
How about this? 这个怎么样?
(defn all-pairs [coll]
(when coll
(concat (map vector (repeat (first coll)) (rest coll))
(all-pairs (next coll)))))
Or, if you seek a lazy seq: 或者,如果你寻求懒惰的seq:
(defn all-pairs [coll]
(lazy-seq
(when coll
(concat (map vector (repeat (first coll)) (rest coll))
(all-pairs (next coll))))))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.