Обновить два значения одновременно в clojure
Мне интересно, как обновить два значения одновременно. Например, я хочу увеличить месяц и одновременно уменьшить возраст. Мой код
user=>(def users {:month 1 :age 26})
user=>(update-in users [:month :age] inc dec)
Я знаю, что этот синтаксис неправильный, но как я могу это исправить? И мне нужно обновить одновременно. Поскольку если я сначала обновлю месяц, а затем обновлю возраст, то первая карта будет потеряна при обновлении второй карты. Или есть другой способ выяснить эту проблему?
3 ответа
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)))
В этом простом случае (обновление функций без дополнительных параметров) вы также можете сделать это следующим образом:
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]}
ну, это еще хуже, чем простое использование потокового макроса.
Обычно я пытаюсь решить эту проблему, написав функцию, которая берет map: keyword -> function и выдает функцию, которая применяет все функции к соответствующим записям записи / карты.
Такая функция
(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}