2014-11-29 31 views
5

Data una mappa con la chiave: contenuto, dove il contenuto è un elenco di stringhe o altre mappe, come posso appiattire i valori per ricevere solo le stringhe?Clojure - Appiattisci ricorsivamente mappe nidificate

(flattener {:content '("b" {:content ("c" {:content ("d")})} "e")}) 

> '("b" "c" "d" "e") 

I'm inciampare attraverso loop molto hacky si ripetono tentativi e ora il mio cervello è bruciato. C'è un bel modo idiomatico per farlo in Clojure?

Grazie.

Quello che ho è inferiore, e anche se funziona, è abbastanza brutto

(defn flatten-content 
    [coll] 
    (loop [acc '(), l coll] 
    (let [fst (first l), rst (rest l)] 
     (cond 
     (empty? l) (reverse acc) 
     (seq? fst) (recur acc (concat fst rst)) 
     (associative? fst) (recur acc (concat (:content fst) rst)) 
     :else (recur (conj acc fst) rst))))) 

risposta

8

La funzione tree-seq aiuta passeggiata, e dal momento che la tua mappa

(def m {:content '("b" {:content ("c" {:content ("d")})} "e")}) 

ha sempre un elenco di " bambini "digitati da :content, questo funziona

(filter string? (tree-seq associative? :content m)) 
;=> ("b" "c" "d" "e") 
+0

piuttosto difficile da battere che per l'eleganza. Grazie. – Scott

5

Th e seguente funzione ricorsiva funziona (ed è circa il 25% più veloce di un filter ndr tree-seq approccio):

(defn flatten-content [node] 
    (lazy-seq 
    (if (string? node) 
     (list node) 
     (mapcat flatten-content (:content node))))) 
Problemi correlati