如何在Clojure中更新矢量项?

时间:2010-02-24 22:51:45

标签: clojure

假设:

(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相同的新向量,除了替换值。

3 个答案:

答案 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?