How to generate a hash map from a list

4,920 views
Skip to first unread message

Stan Dyck

unread,
Aug 23, 2009, 8:21:35 PM8/23/09
to clo...@googlegroups.com
I'm still new to this so bear with me.

I'm trying to apply a function to a seq-able thing to produce a hashmap. So for instance say the function is (inc 3).
I'd like to write a function that does

[1 2 3] --> {1 4, 2 5, 3 6}

Can someone help me?

StanD.

Stephen C. Gilardi

unread,
Aug 24, 2009, 2:18:09 AM8/24/09
to clo...@googlegroups.com

On Aug 23, 2009, at 8:21 PM, Stan Dyck wrote:

> I'm still new to this so bear with me.

Welcome.

> I'm trying to apply a function to a seq-able thing to produce a
> hashmap. So for instance say the function is (inc 3).
> I'd like to write a function that does
>
> [1 2 3] --> {1 4, 2 5, 3 6}
>
> Can someone help me?

Here's one way:

user=> (into {} (for [i [1 2 3]] [i (+ 3 i)]))


{1 4, 2 5, 3 6}

--Steve

Timothy Pratley

unread,
Aug 24, 2009, 2:49:10 AM8/24/09
to Clojure
(def a [1 2 3])

; zipmap takes two collections and makes a hash-map
user=> (zipmap a (map #(+ 3 %) a))
{3 6, 2 5, 1 4}

; another way is to build up a map starting with empty {} and
associating key values
user=> (reduce #(assoc %1 %2 (+ 3 %2)) {} a)
{3 6, 2 5, 1 4}

; hash-map constructs a map for a list of values (use flatten from
contrib/seq-utils to be more concise)
user=> (apply hash-map (filter (complement sequential?) (rest (tree-
seq sequential? seq (for [i a] [i (+ 3 i)])))))
{1 4, 2 5, 3 6}

; into constructs a hashmap from a sequence of key/value pairs
; which is convenient to use with the for list comprehension
user=> (into {} (for [i a] [i (+ 3 i)]))
{3 6, 2 5, 1 4}

Regards,
Tim

ztellman

unread,
Aug 24, 2009, 2:22:42 AM8/24/09
to Clojure
There may be a cleaner solution, but this works:

(defn build-map [s fun]
(apply hash-map (interleave s (map fun s))))

=> (build-map [1 2 3] inc)
{1 2, 2 3, 3 4}

Garth Sheldon-Coulson

unread,
Aug 24, 2009, 2:25:58 AM8/24/09
to clo...@googlegroups.com
Welcome again.

Here's another way. Not sure if it's any more or less efficient, but it's the way my brain works.

=> (defn map-hashmap [coll f]
       (apply hash-map (interleave coll (map f coll))))
#'user/map-hashmap

=> (map-hashmap [1 2 3] #(+ % 3))

{1 4, 2 5, 3 6}

Dragan Djuric

unread,
Aug 24, 2009, 12:15:07 PM8/24/09
to Clojure
(zipmap coll1 coll2) should be faster than (apply hash-map (interleave
coll1 coll2)) and the doc description hints that's what it was made
for.

On Aug 24, 8:25 am, Garth Sheldon-Coulson <g...@mit.edu> wrote:
> Welcome again.
>
> Here's another way. Not sure if it's any more or less efficient, but it's
> the way my brain works.
>
> => (defn map-hashmap [coll f]
>        (apply hash-map (interleave coll (map f coll))))
> #'user/map-hashmap
>
> => (map-hashmap [1 2 3] #(+ % 3))
> {1 4, 2 5, 3 6}
>

samppi

unread,
Aug 24, 2009, 12:43:13 PM8/24/09
to Clojure
Wonderful; I totally didn't know about zipmap. I've been using into
and map this whole time. Was it added right before Clojure 1.0? It
seems to be a lot faster than using into:

Clojure 1.0.0-
user=> (time (into {} (for [i [1 2 3]] [i (+ 3 i)])) )
"Elapsed time: 0.705 msecs"
{3 6, 2 5, 1 4}
user=> (time (zipmap [1 2 3] (map #(+ 3 %) [1 2 3])))
"Elapsed time: 0.25 msecs"
{3 6, 2 5, 1 4}

Adrian Cuthbertson

unread,
Aug 25, 2009, 12:20:22 AM8/25/09
to clo...@googlegroups.com
For completeness we should include a loop/recur pattern;

(defn fzipmap [f col]
"Takes a col, applies f to each element and generates a
hash map keyed on each element of col."
(loop [col (seq col) mp {}]
(if col (recur (next col) (assoc mp (first col) (f (first col))))
mp)))

user=> (fzipmap #(+ % 3) [1 2 3])
{3 6, 2 5, 1 4}

Regards, Adrian.

Adrian Cuthbertson

unread,
Aug 25, 2009, 12:38:03 AM8/25/09
to clo...@googlegroups.com
> (defn fzipmap [f col]
> "Takes a col, applies f to each element and generates a

Note that the args should have come after the doc string!
Reply all
Reply to author
Forward
0 new messages