给定:
(def my-vec [{:id 0 :a "foo" :b "bar"} {:id 1 :a "baz" :b "spam"}
{:id 2 :a "qux" :b "fred"}])
如何用成语更新my-vec中id为:id=1
的项目,并使其具有值:a="baz2"
和:b="spam2"
?
*:我意识到实际上我不会更新my-vec,而是返回一个与my-vec相同但替换值的新向量。
给定:
(def my-vec [{:id 0 :a "foo" :b "bar"} {:id 1 :a "baz" :b "spam"}
{:id 2 :a "qux" :b "fred"}])
如何用成语更新my-vec中id为:id=1
的项目,并使其具有值:a="baz2"
和:b="spam2"
?
*:我意识到实际上我不会更新my-vec,而是返回一个与my-vec相同但替换值的新向量。
您是否事先知道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"}}
对映射向量进行函数映射,如果键匹配,则创建修改后的映射,或者使用原始映射(如果键不匹配),然后将结果转换回向量。
(vec (map #(if (= (:id %) 1)
(assoc % :a "baz2" :b "spam2")
%)))
虽然可以更简洁地完成此操作,但这个方法确实展示了结构共享发生的位置。
(update-in my-vec [1] assoc :a "baz2" :b "spam2")
看起来更干净。 - amalloy