如何将函数应用于(嵌套)映射的叶节点?例如,让我们有这张地图:
{:a 1
:b {:c 2}
:d [{:e 3} {:f 4}]}
假设我们想要增加此映射中的所有叶节点并产生以下结果:
clojure.zip
目前,我正在考虑使用this answer中的map-zipper并通过leaf-node?
函数编辑地图。但是,我不知道如何遍历拉链以及如何识别叶节点。我应该看一下什么功能?有没有拉链的更简单的解决方案吗?
是否可以执行以下工作(假设有一个(require '[clojure.zip :as zip])
(defn inc-leaf-nodes
[loc]
(if (zip/end? loc)
(zip/node loc)
(recur (zip/next (if (leaf-node? loc)
(zip/edit loc inc)
loc)))))
谓词测试拉链中的位置是否为叶节点?)
{{1}}
答案 0 :(得分:4)
可以在给定叶子的适当定义的情况下实现leaf-node?
函数,但建议的inc-leaf-nodes
至少存在两个问题:
您链接到的拉链实现使用地图条目作为节点,因此您不能简单地将inc
传递给zip/edit
- 您必须将其包装在将应用它的辅助函数中价值立场;
拉链也不会将非地图值视为分支,因此它不会下降到向量[{:e 3} {:f 4}]
- 您需要一个不同的拉链来克服这个问题。
假设叶子不是地图,集合或顺序集合,而映射函数仅应用于地图中的值位置,您可以定义map-leaves
函数,如下所示: / p>
(defn map-leaves [f x]
(cond
(map? x) (persistent!
(reduce-kv (fn [out k v]
(assoc! out k (map-leaves f v)))
(transient {})
x))
(set? x) (into #{} (map #(map-leaves f %)) x)
(sequential? x) (into [] (map #(map-leaves f %)) x)
:else (f x)))
在REPL:
(map-leaves inc {:a 0 :b {:c 1 :d [{:e 2} {:f 3}]}})
;= {:a 1, :b {:c 2, :d [{:e 3} {:f 4}]}}
(map-leaves inc {:a 0 :b {:c 1 :d [{:e 2} {:f 3} {:g #{1 2 3}}]}})
;= {:a 1, :b {:c 2, :d [{:e 3} {:f 4} {:g #{4 3 2}}]}}