Reputation: 35692
Suppose I have a map like so
{:a 1 :b 2 :c 3}
I'd like to map over this like so (note - non-working pseudocode):
(mapcat (fn [[:key key-a][:value value-a]] (println "key: " key-a "\n value: " value-a )))
Is this possible without getting the keys of the function first, mapping over those and reading them back from the function?
My question is: How do you destructure a map into key-value pairs without knowing the keys in Clojure?
Upvotes: 6
Views: 3064
Reputation: 13473
(seq {:a 1 :b 2 :c 3})
;([:a 1] [:b 2] [:c 3])
Calling seq
on a map gives you a sequence of key-value pairs. The seq
call is usually implicit.
The pairs
MapEntry
s, which behave as pairs. Thus
(type (first {:a 1 :b 2 :c 3}))
;clojure.lang.MapEntry
Your pseudocode
(mapcat (fn [[:key key-a][:value value-a]] (println "key: " key-a "\n value: " value-a )))
... needs several repairs:
map
is applied.MapEntry
as a pair to get atmap
instead of mapcat
to apply the function to each pair.
It's just lucky that mapcat
works at all. dorun
to force the sequence to evaluate and to throw it away as
it does so. The REPL does the former for you, but a running
application need not. This gives us
(dorun
(map
(fn [[key-a value-a]] (println "key: " key-a " value: " value-a ))
{:a 1 :b 2 :c 3}))
Which prints
key: :a value: 1
key: :c value: 3
key: :b value: 2
... and returns nil
.
Upvotes: 8
Reputation: 5321
When you map
over a map, each element is a vector containing two values: the key and the value. You destructure each element with a vector like this:
(def m {:a 1 :b 2 :c 3})
(map (fn [[key value]] (str "key: " key " > value: " value-a)) m)
Note that the function passed to map
returns a String value, instead of your call to println
, since we're trying to transform the collection passed in by applying a function to each value. You could pass the collection returned by map
to prn
to debug the value, though the REPL will print it out for you anyway.
Upvotes: 5