深度第一个树遍历积累在clojure

Upg*_*ave 3 tree recursion clojure clojurescript

我想采取像这样的树状结构:

{"foo" {"bar" "1" "baz" "2"}}
Run Code Online (Sandbox Code Playgroud)

并且在记住来自根的路径时递归遍历以生成如下内容:

["foo/bar/1", "foo/baz/2"]
Run Code Online (Sandbox Code Playgroud)

关于如何在没有拉链或clojure.walk的情况下如何做到这一点的任何建议?

Thu*_*ail 5

正如nberger所做的那样,我们将枚举路径与它们表示为字符串分开.

列举

功能

(defn paths [x]
  (if (map? x)
    (mapcat (fn [[k v]] (map #(cons k %) (paths v))) x)
    [[x]]))
Run Code Online (Sandbox Code Playgroud)

...返回嵌套映射的路径序列序列.例如,

(paths {"foo" {"bar" "1", "baz" "2"}})
;(("foo" "bar" "1") ("foo" "baz" "2"))
Run Code Online (Sandbox Code Playgroud)

介绍

功能

#(clojure.string/join \/ %)
Run Code Online (Sandbox Code Playgroud)

...将字符串与"/"连接在一起.例如,

(#(clojure.string/join \/ %) (list "foo" "bar" "1"))
;"foo/bar/1"
Run Code Online (Sandbox Code Playgroud)

撰写这些以获得您想要的功能:

(def traverse (comp (partial map #(clojure.string/join \/ %)) paths))
Run Code Online (Sandbox Code Playgroud)

......或者干脆

(defn traverse [x]
  (->> x
      paths
      (map #(clojure.string/join \/ %))))
Run Code Online (Sandbox Code Playgroud)

例如,

(traverse  {"foo" {"bar" "1", "baz" "2"}})
;("foo/bar/1" "foo/baz/2")
Run Code Online (Sandbox Code Playgroud)
  • 你可以将它们作为一个单一的功能缠绕在一起:我认为,将它们分开是更清晰,更有用的.
  • 枚举不是懒惰的,因此它将在足够深的嵌套映射上耗尽堆栈空间.