Clojure:将函数应用于映射的叶节点
如何将函数应用于(嵌套)贴图的叶节点?例如,让我们看一下这张地图:Clojure:将函数应用于映射的叶节点,clojure,Clojure,如何将函数应用于(嵌套)贴图的叶节点?例如,让我们看一下这张地图: {:a 0 :b {:c 1} :d [{:e 2} {:f 3}]} 假设我们希望增加此映射中的所有叶节点,并生成以下结果: {:a 1 :b {:c 2} :d [{:e 3} {:f 4}]} 目前,我正在考虑使用地图拉链,并通过clojure.zip函数编辑地图。但是,我不确定如何遍历拉链以及如何识别叶节点。我应该看什么函数?有没有一个没有拉链的更简单的解决方案 是否可以进行类似以下工作(如果存在叶节点?谓词
{:a 0
:b {:c 1}
:d [{:e 2} {:f 3}]}
假设我们希望增加此映射中的所有叶节点,并生成以下结果:
{:a 1
:b {:c 2}
:d [{:e 3} {:f 4}]}
目前,我正在考虑使用地图拉链,并通过clojure.zip
函数编辑地图。但是,我不确定如何遍历拉链以及如何识别叶节点。我应该看什么函数?有没有一个没有拉链的更简单的解决方案
是否可以进行类似以下工作(如果存在叶节点?
谓词测试zippers中的位置是否为叶节点)
如果叶的定义合适,可以实现
叶节点?
功能,但建议的inc叶节点
至少存在两个问题:
- 您链接到的zipper实现使用地图条目作为节点,因此您不能简单地将
传递到inc
——您必须将其包装在一个助手函数中,该函数将在值位置应用它zip/edit
- 该拉链也不会将非映射值视为分支,因此它不会下降到向量
——您需要一个不同的拉链来解决这个问题[{:e3}{:f4}]
映射叶
函数:
(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}}]}}
谢谢你认为使用
clojure.zip
对这项任务来说是一种过分的手段,还是根本不是一个合适的解决方案?@jindrichm不必担心。只是编辑了答案来解释为什么你链接的拉链不起作用。如果您想在以后的其他转换中使用它,您可以考虑实现一个不同的zipper,但是如果您只对map leaves
感兴趣,以上可能是更简单的方法。(顺便说一句,clojure.walk
是解决此问题的最简单方法,该函数也将应用于关键位置。)
(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}}]}}