2010-10-29 39 views
16

Cho một bộ sưu tập Tôi muốn lặp qua tất cả các cặp trong một bộ sưu tập. Ví dụCách thành ngữ để lặp qua tất cả các cặp của bộ sưu tập trong Clojure

(all-pairs seq) 

(all-pairs '(a b c d)) => ([a b] [a c] [a d] [b c] [b d] [c d])) 

Đây là ý tưởng của tôi

(defn all-pairs [coll] 
    (for [ [idx elmt] (indexed coll) 
     other-elmt (subvec coll (inc idx))] 
    (vector elmt other-elm))) 

Nhưng nó không cảm thấy thành ngữ

Trả lời

17

Làm thế nào về:

(use 'clojure.contrib.combinatorics) 
(vec (map vec (combinations '(a b c d) 2))) 
+0

xin lỗi, không được công nhận, rằng các thùng chứa bên ngoài là một danh sách. Vì vậy, phiên bản chính xác là (bản đồ vec (kết hợp '(a b c d) 2)) – Thomas

+0

+1 cho thực sự sử dụng những gì có sẵn. –

4

Tôi có thể đề nghị:

(defn all-pairs [sq] (for [i sq j sq] [i j])) 

EDIT: Rõ ràng tôi không nhận định các câu hỏi; vì bạn chỉ muốn các cặp không trùng lặp khác nhau, chúng tôi vẫn có thể sử dụng phương pháp này nếu thứ tự tự nhiên tồn tại trên bất kỳ miền nào bạn đang gọi hàm này.

(defn all-pairs [sq] (filter #(< (first %) (second %)) (for [i sq j sq] [i j]))) 

EDIT 2

Ngoài ra:

(defn all-pairs [sq] 
    (partition 2 (flatten (map (fn [sqi] (map #(vector %1 %2) sq sqi)) 
        (take-while not-empty (iterate rest (rest sq))))))) 
+0

Một vấn đề là điều này bao gồm các cụm từ như [b a] và [a a], không bao gồm các từ. –

+0

Vâng, đây là ý tưởng ban đầu của tôi, nhưng nó bao gồm [b a] và [a b]. Tôi chỉ muốn một. – Frank

+0

Tôi thích giải pháp sử dụng khi lọc ra các bản sao: '(cho [a col, b col,: when (> (int a) (int b))] [ab])' –

6

Lazy, và tương đối nhanh.

(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 '(a b c d)) ;; => ([a b] [a c] [a d] [b c] [b d] [c d])

0

Một phiên bản đệ quy đơn giản mà nên làm những gì bạn muốn:

(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))))) 
+0

Tôi nghĩ rằng bạn muốn tạo cuộc gọi đệ quy của bạn với (recur xs) thay vì (tất cả các cặp xs). –

+0

Vâng, nó không phải là, nhưng ngăn xếp sẽ thổi lên. –

+0

Làm sạch một chút: https://gist.github.com/ae0d9ebf85e9ba6e2cb3 – MayDaniel

0

Không phải là giải pháp nhanh nhất, nhưng:

; 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)))) 
6
(defn all-pairs [coll] 
    (loop [[x & xs] coll 
     result []] 
    (if (nil? xs) 
     result 
     (recur xs (concat result (map #(vector x %) xs)))))) 
+0

+1: Câu trả lời này là yêu thích của tôi. –

+0

Nếu hiệu suất là một vấn đề, thay thế 'concat' bằng' conj' áp dụng sẽ tăng tốc độ này một cách đáng kể. –

+0

tuyệt vời! tôi đã tìm kiếm một thành ngữ cho ... mỗi, phá hủy tham số x trong vòng lặp là một ý tưởng tuyệt vời! cảm ơn –

0

Làm thế nào về điều này?

(defn all-pairs [coll] 
(when coll 
    (concat (map vector (repeat (first coll)) (rest coll)) 
      (all-pairs (next coll))))) 

Hoặc, nếu bạn tìm kiếm một seq lười biếng:

(defn all-pairs [coll] 
(lazy-seq 
    (when coll 
    (concat (map vector (repeat (first coll)) (rest coll)) 
      (all-pairs (next coll)))))) 
0

gì về điều này?

(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))))) 
0

Chỉ cần một giải pháp khả thi:

(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]) 
1

Nếu bạn muốn viết combinations chức năng của riêng bạn trong "phong cách học tập", bạn có thể thử

(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))))) 

và sau đó áp dụng nó cho bạn vấn đề như sau

(map vec (comb '(a b c d) 2)) 
([a b] [a c] [a d] [b c] [b d] [c d]) 
+0

Tôi vừa nhận ra (vì StackOverflow đã sắp xếp lại các câu trả lời của ứng viên trên trang) đây là một khái quát rất nhỏ về giải pháp @ mikera bên dưới. –

Các vấn đề liên quan