I seem to chronically run into cases where I want to create a map in Clojure but don’t have just the right tool at hand. One nice function that I’ve found to be helpful is my little friend mapmap. mapmap is probably not a very good name – I’m open to suggestions. Maybe mapmerge would be better. It’s kind of a weird mix of zipmap, merge, and mapcat.
Here’s the code:
(defn mapmap
"Apply kf and vf to a sequence, s, and produce a map of (kf %) to (vf %)."
([vf s]
(mapmap identity vf s))
([kf vf s]
(zipmap (map kf s)
(map vf s))))
This function takes a sequence, and in the three-arg form applies a key function to the sequence, a value function to the values, and zips them together as a map. In the two-arg form, identity is used as the key function so the keys are the original sequence.
Two-arg example:
user> (mapmap #(* 10 %) [1 2 3 4 5])
{5 50, 4 40, 3 30, 2 20, 1 10}
user> (mapmap born-in [ "Chuck Berry" "Ted Nugent" ])
{"Ted Nugent" "Detroit", "Chuck Berry" "St. Louis"}
Three-arg example:
user> (mapmap #(+ 1 %) #(* 10 %) [1 2 3 4])
{5 40, 4 30, 3 20, 2 10}
And I’ve found it useful to use mapmap over a map as a sequence of map entries, for example to take a map and manipulate either the keys and/or the values of the map.
user> (mapmap #(subs (key %) 0 2)
(comp name val)
{ "abcd" :x, "foobar" :y, "nachos" :z })
{"na" "z", "fo" "y", "ab" "x"}
Or if for example you wanted to swap the keys and values in a map:
user> (mapmap val key { :a 1 :b 2 :c 3 })
{3 :c 2 :b 1 :a}
What do you think?
