在Clojure中使用traversy/lens更新不存在的Map路径
Clojure中使用traversy.lens更新嵌套路径(含不存在路径)的问题
现有数据
原始Clojure Map r:
{:a1 {:foo {:xyz "xyz" :abc []} } :a2 {:bar {:xyz "xyz" :abc []} } :a3 {:baz {:xyz "xyz" :abc []} } :a4 {:bax {:xyz "xyz"}} :a5 {} :b1 {:abc []}}
需求
需更新以下路径的值为"new_val":已存在的数组路径追加元素,不存在的路径自动创建嵌套结构并设置初始数组:
:a1 :foo :abc:a2 :bar :abc:a3 :baz :abc:a4 :bax :abc:a5 :bay :abc
尝试的代码
(traversy.lens/update r (traversy.lens/+> (traversy.lens/in [:a1 :foo :abc]) (traversy.lens/in [:a2 :bar :abc]) (traversy.lens/in [:a3 :baz :abc]) (traversy.lens/in [:a4 :bax :abc]) (traversy.lens/in [:a5 :bay :abc])) #(if % (conj % "new_val") (assoc :abc [ "new_val"])))
当前执行结果
{:a1 {:foo {:xyz "xyz", :abc ["new_val"]}}, :a2 {:bar {:xyz "xyz", :abc ["new_val"]}}, :a3 {:baz {:xyz "xyz", :abc ["new_val"]}}, :a4 {:bax {:xyz "xyz"}}, :a5 {}, :b1 {:abc []}}
可见:a4 :bax :abc和:a5 :bay :abc因路径不存在未被更新。
期望结果
{:a1 {:foo {:xyz "xyz" :abc ["new_val"]}}, :a2 {:bar {:xyz "xyz" :abc ["new_val"]}}, :a3 {:baz {:xyz "xyz" :abc ["new_val"]}}, :a4 {:bax {:xyz "xyz" :abc ["new_val"]}}, :a5 {:bay {:xyz "xyz" :abc ["new_val"]}}, :b1 {:abc []}}
解决方案
问题根源有两点:
traversy.lens/in仅处理已存在的路径,不会自动创建缺失的嵌套Map结构;- 更新函数中路径不存在时的逻辑错误(
assoc :abc ["new_val"]缺少Map参数,正确应直接返回目标数组)。
修正后的代码
使用traversy.lens/ensure替代in(自动创建缺失的中间嵌套Map),同时修正更新逻辑:
(traversy.lens/update r (traversy.lens/+> (traversy.lens/ensure [:a1 :foo :abc]) (traversy.lens/ensure [:a2 :bar :abc]) (traversy.lens/ensure [:a3 :baz :abc]) (traversy.lens/ensure [:a4 :bax :abc]) (traversy.lens/ensure [:a5 :bay :abc])) #(if % (conj % "new_val") ["new_val"]))
适配:xyz默认值的补充代码
如果需要新建的:bax/:bay自动包含:xyz "xyz"(和期望结果完全匹配),可以封装路径处理逻辑:
(defn update-path-with-xyz [path] (traversy.lens/+> ;; 确保父路径存在,添加默认的:xyz键 (traversy.lens/ensure (butlast path)) (traversy.lens/in (butlast path)) #(assoc % :xyz "xyz") ;; 处理目标abc路径 (traversy.lens/ensure path) (traversy.lens/in path) #(if % (conj % "new_val") ["new_val"]))) (traversy.lens/update r (traversy.lens/+> (update-path-with-xyz [:a1 :foo :abc]) (update-path-with-xyz [:a2 :bar :abc]) (update-path-with-xyz [:a3 :baz :abc]) (update-path-with-xyz [:a4 :bax :abc]) (update-path-with-xyz [:a5 :bay :abc])))
内容的提问来源于stack exchange,提问作者user51
相关产品推荐
相关产品推荐

