I would like to get the nth element of the nested map, but could not find the appropriate command and had got an error. I would need something that worked like a first
function:
boot.user=> (def db2 @main/database)
#'boot.user/db2
boot.user=> (def ims (get-in db2 [kl :items]))
#'boot.user/ims
boot.user=> ims
{"i15059" {:name "ESS1", :done? false}, "i15064" {:name "ESS2", :done? false}, "i15114" {:name "ESS3", :done? false}, "i15121" {:name "ESS3", :done? false}}
boot.user=> (first ims)
["i15059" {:name "ESS1", :done? false}]
boot.user=> (nth ims 1)
java.lang.UnsupportedOperationException: nth not supported on this type: PersistentArrayMap
boot.user=>
Any suggestions?
A map is unordered (unless you explicitly created a sorted-map
). When you get the map entries (such as a for
loop or first
), Clojure silently calls seq
on the map to get a "list-like" sequence of MapEntry
items:
(def mappy {:c 3 :d 4 :a 1 :b 2 })
mappy => {:c 3, :d 4, :a 1, :b 2}
(seq mappy) => ([:c 3] [:d 4] [:a 1] [:b 2])
(vec mappy) => [[:c 3] [:d 4] [:a 1] [:b 2]]
(first mappy) => [:c 3]
Note that a seq
prints like a list, but isn't. A MapEntry prints like a vector, but isn't.
(seq mappy) => <#clojure.lang.PersistentArrayMap$Seq ([:c 3] [:d 4] [:a 1] [:b 2])>
(first mappy) => <#clojure.lang.MapEntry [:c 3]>
Once you have some sequential object (vector, list, or seq), you can use nth
to get the items one at a time:
(let [mapseq (seq mappy)
mapvec (vec mappy) ]
(nth mapseq 3) => [:b 2]
(nth mapvec 3) => [:b 2]
However, note that the returned item is still a MapEntry
, not a 2-vector.
(nth mapseq 3) => <#clojure.lang.MapEntry [:b 2]>
(nth mapvec 3) => <#clojure.lang.MapEntry [:b 2]>
You can get the key and value from the MapEntry using key
and val
functions:
(key (nth mapseq 3)) => :b
(val (nth mapvec 3)) => 2
P.S. You can print a value & its type as above using the spyxx
function.