按路径模式访问 clojure.zip 树
visit clojure.zip tree by path pattern
假设我有一棵我想访问的树 - 这应该包括修改访问项目的可能性 - 所有与路径匹配的项目
(def visit-path [:b :all :x :all])
这里我使用:all
作为通配符来匹配所有的子节点。在下面的示例树中,
(def my-tree
{:a "a"
:b
{:b-1
{:x
{:b-1-1 "b11"
:b-1-2 "b12"}}
:b-2
{:x
{:b-2-1 "b21"}}}})
那将是项目
- [:b-1-1 "b11"]
- [:b-1-2 "b12"]
- [:b-2-1 "b21"]
有没有使用 clojure 核心的优雅方法?
仅供参考,我确实通过创建自己的模式访问者解决了这个问题
(defn visit-zipper-pattern
[loc pattern f]
但是虽然这个函数一般可用,但它非常复杂,结合了堆栈消耗递归和尾调用递归。所以当像
这样调用那个方法时
(visit-zipper-pattern (map-zipper my-tree) visit-path
(fn [[k v]] [k (str "mod-" v)]))
使用 中的 map-zipper
,它将树转换为
{:a "a"
:b {:b-1
{:x
{:b-1-1 "mod-b11"
:b-1-2 "mod-b12"}}
:b-2
{:x
{:b-2-1 "mod-b21"}}}}
以下将起作用 - 请注意 1) 它可能会在处理 :all
键时分配不需要的对象,并且 2) 您需要决定如何处理边缘情况,例如 :all
on non-map离开。
(defn traverse [[k & rest-ks :as pattern] f tree]
(if (empty? pattern)
(f tree)
(if (= k :all)
(reduce #(assoc %1 %2 (traverse rest-ks f (get tree %2)))
tree (keys tree))
(cond-> tree (contains? tree k)
(assoc k (traverse rest-ks f (get tree k)))))))
为了获得更有效的解决方案,最好使用上面推荐的 https://github.com/nathanmarz/specter。
假设我有一棵我想访问的树 - 这应该包括修改访问项目的可能性 - 所有与路径匹配的项目
(def visit-path [:b :all :x :all])
这里我使用:all
作为通配符来匹配所有的子节点。在下面的示例树中,
(def my-tree
{:a "a"
:b
{:b-1
{:x
{:b-1-1 "b11"
:b-1-2 "b12"}}
:b-2
{:x
{:b-2-1 "b21"}}}})
那将是项目
- [:b-1-1 "b11"]
- [:b-1-2 "b12"]
- [:b-2-1 "b21"]
有没有使用 clojure 核心的优雅方法?
仅供参考,我确实通过创建自己的模式访问者解决了这个问题
(defn visit-zipper-pattern
[loc pattern f]
但是虽然这个函数一般可用,但它非常复杂,结合了堆栈消耗递归和尾调用递归。所以当像
这样调用那个方法时(visit-zipper-pattern (map-zipper my-tree) visit-path
(fn [[k v]] [k (str "mod-" v)]))
使用 中的 map-zipper
,它将树转换为
{:a "a"
:b {:b-1
{:x
{:b-1-1 "mod-b11"
:b-1-2 "mod-b12"}}
:b-2
{:x
{:b-2-1 "mod-b21"}}}}
以下将起作用 - 请注意 1) 它可能会在处理 :all
键时分配不需要的对象,并且 2) 您需要决定如何处理边缘情况,例如 :all
on non-map离开。
(defn traverse [[k & rest-ks :as pattern] f tree]
(if (empty? pattern)
(f tree)
(if (= k :all)
(reduce #(assoc %1 %2 (traverse rest-ks f (get tree %2)))
tree (keys tree))
(cond-> tree (contains? tree k)
(assoc k (traverse rest-ks f (get tree k)))))))
为了获得更有效的解决方案,最好使用上面推荐的 https://github.com/nathanmarz/specter。