在clojure

时间:2016-04-26 18:36:16

标签: clojure update-in

我想知道如何同时更新两个值。例如,我想同时增加月份和减少年龄。我的代码是

user=>(def users {:month 1 :age 26})
user=>(update-in users [:month :age] inc dec)

我知道这种语法不正确,但我该如何解决这个问题呢?我需要同时更新。因为如果我先更新月份然后更新年龄,那么当我更新第二张地图时,第一张地图将丢失。或者还有其他方法来解决这个问题吗?

3 个答案:

答案 0 :(得分:5)

update不修改值,只返回一个新值,因此它只是一个函数。如果您需要更新地图的2个字段,那么直接的方法就是调用update两次,首先在原始地图上,然后是第一次更新的结果:

(defn update-month-and-age [user]
  (update (update user :month inc) :age dec))

使用->看起来更好:

(defn update-month-and-age [user]
  (-> user
      (update :month inc)
      (update :age dec)))

答案 1 :(得分:2)

在这个简单的情况下(没有附加参数的更新函数)你也可以这样做:

user> (def users {:month 1 :age 26 :records [1 2 3]})
#'user/users

user> (reduce-kv update users {:month inc :age dec :records reverse})
{:month 2, :age 25, :records (3 2 1)}

有了额外的参数,它会更加冗长:

user> (reduce-kv (partial apply update)
                 users
                 {:month [+ 2] :age [dec] :records [conj 101]})
{:month 3, :age 25, :records [1 2 3 101]}
好吧,它比使用线程宏更简单。

答案 2 :(得分:0)

我很想通过编写一个带有地图的函数来解决这个问题:关键字 - >函数,并生成一个函数,将所有函数应用于相关的记录/映射条目。

这样的功能是

(defn field-updater [fn-map]
  (fn [record]
    (reduce
     (fn [m [k f]] (assoc m k (f (m k))))
     record
     fn-map)))

我们使用它来生成所需的字段更新程序:

(def update-in-users (field-updater {:month inc :age dec}))

...然后我们可以申请

(update-in-users users)
;{:month 2, :age 25}