Clojure:如何在向量中创建或更新Map的值
Clojure 向量元素更新实现
需求说明
原向量:
[{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 5, :value2 300}}]
需要修改为:
[{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 6, :value2 500}}]
你的代码问题分析
你写的代码存在几个关键问题:
contains? myvectors myId用法错误:contains?用于检查集合的键是否存在,向量的键是索引(0、1这类数值),不是元素内部的:key值,因此无法判断目标元素是否存在。- Clojure是不可变数据结构,
assoc不会修改原数据,而是返回新对象,你的代码没有将结果赋值保存。 merge不能用来合并向量和map:merge是针对map的操作,向量添加元素应该用conj。- 语法错误:
if的括号嵌套逻辑混乱,第二个do块的位置不符合语法规范。
正确实现方法
方法一:遍历匹配更新(推荐)
通过mapv遍历每个元素,找到:key匹配myId的元素时,深层更新:values里的字段,其他元素保持不变:
(def myvectors [{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 5, :value2 300}}]) (def myId 1) ;; 执行更新 (def updated-vectors (mapv (fn [item] (if (= (:key item) myId) (update-in item [:values] merge {:value1 6, :value2 500}) item)) myvectors))
mapv返回向量(map返回的是序列),update-in用于深层更新嵌套结构,merge负责将新键值对合并到:values中。
方法二:索引定位更新
先找到目标元素的索引,再用update-in直接更新对应位置的嵌套字段,不存在则添加新元素:
(def myvectors [{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 5, :value2 300}}]) (def myId 1) ;; 查找目标元素索引 (def target-index (first (keep-indexed #(when (= (:key %2) myId) %1) myvectors))) ;; 更新或添加元素 (def updated-vectors (if target-index (update-in myvectors [target-index :values] merge {:value1 6, :value2 500}) (conj myvectors {:key myId, :values {:value1 1, :value2 300}})))
keep-indexed遍历向量并返回匹配元素的索引,update-in直接定位嵌套路径更新,不存在时用conj将新元素添加到向量末尾。
优化建议
如果需要频繁按:key进行查找更新,建议把向量转换成以:key值为键的map,操作效率更高:
;; 向量转map (def mymap (into {} (map #(vector (:key %) %) myvectors))) ;; 更新map中的元素 (def updated-map (update mymap myId #(update-in % [:values] merge {:value1 6, :value2 500}))) ;; 转回向量 (def updated-vectors (vals updated-map))
内容的提问来源于stack exchange,提问作者Noweh
相关产品推荐
相关产品推荐

