2013-06-27 20 views
7
(def threads 
    {:values 
    [{:_id "t1" 
    :u {:uid 1} 
    :members {:values [{:uid 1} {:uid 2}]} 
    :messages {:values 
       [{:_id "m1" :u {:uid 1}} 
       {:_id "m2" :u {:uid 2}}]}} 
    {:_id "t2" 
    :u {:uid 12} 
    :members {:values [{:uid 11} {:uid 12}]} 
    :messages {:values 
       [{:_id "m3" :u {:uid 13}} 
       {:_id "m4" :u {:uid 12}}]}}]}) 

Cần phải tìm hiểu tất cả các giá trị cho khóa: uid Trong trường hợp này câu trả lời nên trả lại [1 2 11 12 13] mà không sử dụng bất kỳ toàn cầu ràng buộc. Cần quy mô giải pháp cho bất kỳ cấp độ nào của cấu trúc lồng nhau.Làm thế nào để có được tất cả các giá trị cho khóa được đưa ra trong một cấu trúc lồng nhau trong clojure

Cảm ơn

Trả lời

9

Điều này có thể được thực hiện với bộ lọc và bộ lọc, hoặc khi đi bộ. Cả hai appraoches là thú vị với tôi:

cây seq:

user> (map :uid 
      (filter #(if (and (map? %) (:uid %)) true false) 
        (tree-seq #(or (map? %) (vector? %)) identity threads))) 
(1 2 1 1 2 13 12 12 11 12) 

nào trông đẹp hơn khi luồng ra với ->> (và với các thiết lập và vec để loại bỏ dups)

user> (->> (tree-seq #(or (map? %) (vector? %)) identity threads) 
      (filter #(if (and (map? %) (:uid %)) true false)) 
      (map :uid) 
      set 
      vec)         
[1 2 11 12 13] 

hoặc với postwalk :

user> (let [results (atom [])] 
     (clojure.walk/postwalk 
      #(do (if-let [uid (:uid %)] (swap! results conj uid)) %) 
      threads) 
     @results) 
[1 2 1 1 2 13 12 12 11 12] 

Điều này đi theo cấu trúc với hàm, nếu đường ucture chứa một khóa có tên: uid, gắn nó vào một nguyên tử cục bộ. Sau đó, cuối cùng trả lại các nội dung tích lũy của nguyên tử. Điều này hơi khác so với ví dụ của bạn bởi vì nó tích lũy các bản sao. Nếu bạn muốn loại bỏ chúng một cách hiệu quả thì hãy sử dụng một bộ làm bộ tích lũy thay vì một vectơ, sau đó biến nó thành một vectơ một lần ở cuối (ví dụ của bạn có kết quả trong một vectơ)

user> (let [results (atom #{})] 
     (clojure.walk/postwalk 
      #(do (if-let [uid (:uid %)] (swap! results conj uid)) %) 
      threads) 
     (vec @results)) 
[1 2 11 12 13] 
+0

Cảm ơn Arthur. Tôi thích câu trả lời của cây-seq hơn. Khi tôi đã bắt đầu sử dụng clojure - tôi thích các bước của dữ liệu-trong-> dữ liệu-out hơn phương pháp tiếp cận nguyên tử. Học một cái gì đó mới ngày hôm nay - cảm ơn rất nhiều :) –

+1

'(bản đồ: uid (filter # (if (và (map?%) (: Uid%)) true false) coll))' có thể được thay thế bằng chỉ '(giữ: uid coll) '. – amalloy

+0

ohhh, ưa thích :) Tôi thích giao diện tốt hơn nhiều. –

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