You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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 []}}

解决方案

问题根源有两点:

  1. traversy.lens/in仅处理已存在的路径,不会自动创建缺失的嵌套Map结构;
  2. 更新函数中路径不存在时的逻辑错误(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 06:51:18