2013-06-27 19 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}}]}}]}) 

trzeba sprawdzić wszystkie wartości dla klucza: uid W tym przypadku odpowiedź powinna powrócić [1 2 11 12 13] bez użycia globalny wiązania. Potrzebuje skali rozwiązania dla dowolnego poziomu struktury zagnieżdżonej.Jak zdobyć wszystkie wartości dla danego klucza w zagnieżdżonej struktury w Clojure

Dzięki

Odpowiedz

9

Można to zrobić z drzewa-seq i filtra lub z post-spacer. Oba appraoches są interesujące dla mnie jest:

drzewa nast:

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) 

Która wygląda lepiej, gdy gwintowany się z ->> (iz zestawu i vec usunąć 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] 

lub z 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] 

To podchodzi do struktury z funkcją, która, jeśli ucture zawiera klucz o nazwie: uid, dołącza go do lokalnego atomu. Następnie na końcu zwróć zgromadzoną zawartość atomu. Różni się to nieznacznie od twojego przykładu, ponieważ gromadzi duplikaty. Jeśli chcesz je skutecznie wyeliminować, użyj zestawu jako akumulatora zamiast wektora, a następnie przekształć go w wektor raz na końcu (Twój przykład daje w rezultacie wektor)

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

Dzięki Arthur. Lubię więcej odpowiedzi na pytanie o drzewo. Jak już zacząłem używać clojure - lubię kroki danych-w-danych-out bardziej niż podejścia atomowe. Nauczyłem się czegoś nowego dzisiaj - wielkie dzięki :) –

+1

'(map: uid (filter # (if (and (map?%) (: Uid%)) true false) coll))' może być zastąpione właśnie '(keep: uid coll) '. – amalloy

+0

ohhh, fantazyjnie :) Podoba mi się wygląd tego o wiele lepiej. –

Powiązane problemy