ClojureDocs

Nav

Namespaces

update-in

clojure.core

Available since 1.0 (source)
  • (update-in m ks f & args)
'Updates' a value in a nested associative structure, where ks is a
sequence of keys and f is a function that will take the old value
and any supplied args and return the new value, and returns a new
nested structure.  If any levels do not exist, hash-maps will be
created.
11 Examples
(def users [{:name "James" :age 26}  {:name "John" :age 43}])
;;=> #'user/users

;; similar to assoc-in but does not simply replace the item.
;; the specified function is performed on the matching item.
;; here the age of the second (index 1) user is incremented.
(update-in users [1 :age] inc)
;;=> [{:name "James", :age 26} {:name "John", :age 44}]
(def p {:name "James" :age 26})
;;=> #'user/p

(update-in p [:age] inc)
;;=> {:name "James", :age 27}

;; remember, the value of p hasn't changed!
(update-in p [:age] + 10)
;;=> {:name "James", :age 36}

;; Here we see that the keyed object is 
;; the first argument in the function call.
;; i.e. :age (- 26 10) => 16
(update-in p [:age] - 10)
;;=> {:name "James", :age 16}
(defn char-cnt [s]
  "Counts occurence of each character in s"
  (reduce
    (fn [m k]
      (update-in m [k] (fnil inc 0)))
  {}
  s))
;; Note use of fnil above 
;; - returns 0 if nil is passed to inc (avoids null pointer exception)

(char-cnt "foo-bar")
;;=> {\r 1, \a 1, \b 1, \- 1, \o 2, \f 1}
;; f has args
;; The keyed value is placed as the first argument
;; :a  (/ 3 4 5) => 3/20 
(update-in {:a 3} [:a] / 4 5)
;;=> {:a 3/20}
;; be careful with that empty path sequence, it's seldom what you want
(update-in {} [] (constantly {:k :v}))
;;=> {nil {:k :v}}

;; In general, you find that for a non-empty path
;;   (get-in (update-in m path (constantly v)) path) 
;; is equal to v.
;; Surprisingly this does not hold true in case of an empty path.
;;You can use update-in in a nested map too, in order to update more than
;;one value:

(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})

(update-in m [:1] assoc :value 1 :active true)
;;=>{:1 {:value 1, :active true}, :2 {:value 0, :active false}}
;; We may dig into multiple levels with `update-in`:
(def player1 {:name "Player 1" :attribs {:str 10 :int 11 :wis 9}})

(update-in player1 [:attribs :str] inc)
;; {:name "Player 1", :attribs {:str 11, :int 11, :wis 9}}

(update-in player1 [:attribs :str] * 2)
;; {:name "Player 1", :attribs {:str 20, :int 11, :wis 9}}

;; We can see one level via `update`...

(update player1 :attribs #(update % :str inc))
;; {:name "Player 1", :attribs {:str 11, :int 11, :wis 9}}
user=> (update-in {:a {:b 3}} [:a :b] inc)

;;=> {:a {:b 4}}
;; can also use in []

user=> (update-in [1 2 [1 2 3]] [2 0] inc)
;;=> [1 2 [2 2 3]]
;; can mix associative types as well

user=> (update-in [1 {:a 2 :b 3 :c 4}] [1 :c] (fnil inc 5))
;; => [1 {:a 2, :b 3, :c 5}]
user=> (update-in [1 {:a 2 :b 3 :c 4}] [1 :d] (fnil inc 5))
;; => [1 {:a 2, :b 3, :c 4, :d 6}]

;; but of course vector indices must be appropriate types

user=> (update-in [1 {:a 2 :b 3 :c 4}] [:b :c] (fnil inc 5))
IllegalArgumentException Key must be integer  clojure.lang.APersistentVector.assoc (APersistentVector.java:345)
(def ds [{:id 1.0 :name "name1"}
         {:id 2.0 :name "name2"}
         {:id 3.0 :name "name3"}])

(map (fn [x] (update-in x [:name] #(if (= "name2" %) % "not 2"))) ds)

;; | :id | :name |
;; |-----+-------|
;; | 1.0 | not 2 |
;; | 2.0 | name2 |
;; | 3.0 | not 2 |
See Also

Associates a value in a nested associative structure, where ks is a sequence of keys and v is the ...

Added by zk

Returns the value in a nested associative structure, where ks is a sequence of keys. Returns nil i...

Added by jks

Takes a function f, and returns a function that calls f, replacing a nil first argument to f with ...

Added by eric

'Updates' a value in an associative structure, where k is a key and f is a function that will take...

Added by brunchboy

Returns true if coll implements Associative

Added by xmo-odoo
0 Notes
No notes for update-in