Clojure - 递归展开嵌套映射

6

如果给你一个包含键名为“content”的地图,其中content是字符串或其他地图的列表,我该如何将这些值展开并仅获取字符串?

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

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

我正在尝试使用非常hacky的loop recur方法,现在我的大脑已经崩溃了。在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)))))
2个回答

10

tree-seq 函数帮助遍历,同时由于你的映射表

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

始终有一个由:content键控的“子项”列表,这样可以正常工作

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

很难超越这种优雅。谢谢。 - Scott Klarenbach

5
下面的递归函数可行(且比使用过滤器的tree-seq方法快约25%):
(defn flatten-content [node]
  (lazy-seq
    (if (string? node)
      (list node)
      (mapcat flatten-content (:content node)))))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接