想象一下,你有这样的地图:
(def person {
:name {
:first-name "John"
:middle-name "Michael"
:last-name "Smith" }})
更改与两者相关的值的惯用方法是什么:first-name和:last-name在一个表达式中?
(澄清:假设您要设置:名字为“Bob”,并且姓氏为“Doe”。我们还要说这个地图中还有其他一些我们要保留的值,所以构建从头开始不是一个选项)
答案 0 :(得分:42)
以下是两种方式。
user> (update-in person [:name] assoc :first-name "Bob" :last-name "Doe")
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
user> (update-in person [:name] merge {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
user> (update-in person [:name] into {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
user> (-> person
(assoc-in [:name :first-name] "Bob")
(assoc-in [:name :last-name] "Doe"))
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
update-in
在您的地图上执行递归assoc
。在这种情况下,它大致相当于:
user> (assoc person :name
(assoc (:name person)
:first-name "Bob"
:last-name "Doe"))
当您深入了解一系列嵌套地图时,重复键会变得越来越乏味。 update-in
的递归可以避免一遍又一遍地重复键(例如:name
);中间结果存储在递归调用之间的堆栈上。查看update-in的来源,看看它是如何完成的。
user> (def foo {:bar {:baz {:quux 123}}})
#'user/foo
user> (assoc foo :bar
(assoc (:bar foo) :baz
(assoc (:baz (:bar foo)) :quux
(inc (:quux (:baz (:bar foo)))))))
{:bar {:baz {:quux 124}}}
user> (update-in foo [:bar :baz :quux] inc)
{:bar {:baz {:quux 124}}}
assoc
是动态的(与update-in
,assoc-in
一样,以及在Clojure数据结构上运行的大多数其他Clojure函数。如果将assoc
放到地图上,则会返回地图。如果你assoc
到一个向量上,它会返回一个向量。查看assoc的来源,并查看Clojure源代码中的RT.java
了解详细信息。