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?