简体   繁体   English

Clojure - 递归展平嵌套地图

[英]Clojure - Recursively Flatten Nested Maps

Given a map with the key :content, where content is a list of strings or other maps, how can I flatten out the values to receive only the strings? 给定一个带有键的映射:content,其中content是字符串列表或其他映射,如何将值展平以仅接收字符串?

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

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

I'm stumbling through very hacky loop recur attempts and now my brain is burnt out. 我正在磕磕绊绊地进行非常粗暴的循环重复尝试,现在我的大脑被烧毁了。 Is there a nice idiomatic way to do this in Clojure? 在Clojure中有一个很好的惯用方法吗?

Thanks. 谢谢。

What I've got is below, and although it works, it's quite ugly 我得到的是下面的,虽然它有效,但它很难看

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

The tree-seq function helps walk, and since your map tree-seq函数可以帮助您行走,也可以自动映射

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

always has a list of "children" keyed by :content , this works 总是有一个“孩子”的列表键入:content ,这是有效的

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

The following recursive function works (and is about 25% faster than a filter ed tree-seq approach): 以下递归函数有效(并且比filter ed tree-seq方法快25%):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM