假设:
(def my-vec [{:id 0 :a "foo" :b "bar"} {:id 1 :a "baz" :b "spam"}
{:id 2 :a "qux" :b "fred"}])
我如何通过:id=1
惯性更新my-vec中的项目,以获得值:a="baz2"
和:b="spam2"
?
*:我认识到我实际上不会更新my-vec,但实际上会返回一个与my-vec相同的新向量,除了替换值。
答案 0 :(得分:10)
您是否提前知道id == 1的地图是向量中的第二张地图?如果是这样的话:
user> (-> my-vec
(assoc-in [1 :a] "baz2")
(assoc-in [1 :b] "spam2"))
[{:id 0, :a "foo", :b "bar"} {:id 1, :a "baz2", :b "spam2"} {:id 2, :a "qux", :b "fred"}]
如果你需要通过id访问你的数据,另一个想法是用:id
上键入的哈希映射的哈希映射替换你的哈希映射向量。然后,无论事情顺序如何,您都可以更轻松assoc-in
。
user> (def new-my-vec (zipmap (map :id my-vec) my-vec))
#'user/new-my-vec
user> new-my-vec
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz", :b "spam"}, 0 {:id 0, :a "foo", :b "bar"}}
user> (-> new-my-vec
(assoc-in [1 :a] "baz2")
(assoc-in [1 :b] "spam2"))
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz2", :b "spam2"}, 0 {:id 0, :a "foo", :b "bar"}}
答案 1 :(得分:8)
在地图矢量上映射函数,如果键匹配则创建修改后的映射,如果键不匹配则使用原始映射,然后将结果转换回矢量
(vec (map #(if (= (:id %) 1)
(assoc % :a "baz2" :b "spam2")
%)))
可以更简洁地做到这一点,尽管这个确实显示了结构共享发生的位置。
答案 2 :(得分:3)
可能要查看array-map,它会创建一个由数组支持的地图并使用索引键入而不是使用:id?