2014-11-29 2 views
5

Учитывая карту с ключом: содержимое, где содержимое представляет собой список строк или других карт, как я могу сгладить значения, чтобы получать только строки?Clojure - рекурсивно сгладить вложенные карты

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

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

Я натыкаюсь на попытки взлома хакерской петли, и теперь мой мозг сгорел. Есть ли хороший идиоматический способ сделать это в Clojure?

Спасибо.

Что у меня ниже, и, хотя он работает, это довольно некрасиво

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

ответ

8

tree-seq функция помогает ходить, а с вашей карты

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

всегда есть список " дети ", введенные в действие :content, это работает

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

Довольно трудно превзойти, что для элегантности. Благодарю. – Scott

5

Th е рекуррентная функция работает (и составляет около 25% быстрее, чем filter эд tree-seq подхода):

(defn flatten-content [node] 
    (lazy-seq 
    (if (string? node) 
     (list node) 
     (mapcat flatten-content (:content node))))) 
Смежные вопросы