get-in

added
1.2

ns
clojure.core

type
function

(get-in m ks) (get-in m ks not-found)

Returns the value in a nested associative structure,
where ks is a sequence of keys. Returns nil if the key
is not present, or the not-found value if supplied.

                ;; We can use get-in for reaching into nested maps:
user=> (def m {:username "sally"
               :profile {:name "Sally Clojurian"
                         :address {:city "Austin" :state "TX"}}})
#'user/m

user=> (get-in m [:profile :name])
"Sally Clojurian"
user=> (get-in m [:profile :address :city])
"Austin"
user=> (get-in m [:profile :address :zip-code])
nil
user=> (get-in m [:profile :address :zip-code] "no zip code!")
"no zip code!"


;; Vectors are also associative:
user=> (def v [[1 2 3]
               [4 5 6]
               [7 8 9]])
#'user/v
user=> (get-in v [0 2])
3
user=> (get-in v [2 1])
8


;; We can mix associative types:
user=> (def mv {:username "jimmy"
                :pets [{:name "Rex"
                        :type :dog}
                       {:name "Sniffles"
                        :type :hamster}]})
#'user/mv
user=> (get-in mv [:pets 1 :type])
:hamster

            
                (def s1 [[:000-00-0000 "TYPE 1" "JACKSON" "FRED"]
         [:000-00-0001 "TYPE 2" "SIMPSON" "HOMER"]
         [:000-00-0002 "TYPE 4" "SMITH" "SUSAN"]])

(def cols [0 2 3])

(defn f1 
  [s1 col] 
  (map #(get-in s1 [% col] nil) (range (count s1))))

(apply interleave (map (partial f1 s1) cols))

(:000-00-0000 "JACKSON" "FRED" :000-00-0001 "SIMPSON" "HOMER" :000-00-0002 "SMITH" "SUSAN")
            
                ;; spam link removed
            
                ;; Introduction of references is jarring to get-in usage

(def owners [{:owner "Jimmy"
              :pets (ref [{:name "Rex"
                           :type :dog}
                          {:name "Sniffles"
                           :type :hamster}])} 
              {:owner "Jacky" 
               :pets (ref [{:name "Spot" 
                            :type :mink}
                           {:name "Puff" 
                            :type :magic-dragon}])}])
;;=> 'user/owners

(get-in owners [0 :pets])
;;=> #<Ref@: [{:name "Rex", :type :dog} {:name "Sniffles", :type :hamster}>

;; In order to go deeper the get needs to be split 
;; as the deref cannot be used as part of the get.
(-> (get-in owners [0 :pets]) deref (get-in [1 :type]))
;;=> :hamster

;; At this point it clear that the thread operator 
;; can be used to produce similar results. 
(-> owners (nth 0) :pets deref (nth 1) :type)
;;=> :hamster
            
                ;; If the nested structure contains list, it does not work, because list is 
;; not an associative structure.
(def a {:a '({:b1 2} {:b2 4}) :c 3})
;;=> 'user/a
(get-in a [:a 0 :b])
;;=> nil
            
                ;; If an empty sequence is used as keys, the whole structure is returned.
(get-in {:a 1 :b 2} [])
;;=> {:a 1, :b 2}
(get-in {:a 1, :b 2} '())
;;=> {:a 1, :b 2}

;; nil also counts as an empty sequence!
(get-in {:a 1 :b 2} nil)
;;=> {:a 1, :b 2}

;; Be careful if you use a nill-able key sequence with not-found value.
;; This can be a source of bug.
(get-in {:a 1 :b 2} nil :nothing)
;;=> {:a 1, :b 2}