Python like hash-map constructor (a.k.a. dict)

586 views
Skip to first unread message

Henk

unread,
Oct 14, 2010, 11:54:00 AM10/14/10
to Clojure
Hi All,

In Python I was used to be able to easily create dictionaries from
lists of key value 'pairs' (tuples or list), e.g. like this:

dict([(10, 20), (30, 40)]) #using the dict constructor
=>
{10:20, 30:40}

What would be the equivalent in Clojure?, e.g. the normal Clojure hash-
map function takes a list
of alternating keys and values which is not quite the same.
This is a quite common need (especially in the context of initializing
a hash-map from a list comprehension, like this:

(dict (for [x programmers :when ((x :-p rogramming_skills) :java)]
[(x :id) (str (x :firstname) " " (x :lastname))]))

This function seems to do the trick:

(defn dict [x] (apply hash-map (apply concat x)))

but it is quite slow, e.g. much slower than the python native version
(I did some small benchmarks on this), while the list comprehension
itself is much faster than python...

liebke

unread,
Oct 14, 2010, 12:20:07 PM10/14/10
to Clojure
Here's one approach:

(into {} [[:a 1] [:b 2] [:c 3]])

=> {:a 1, :b 2, :c 3}

Chris Perkins

unread,
Oct 14, 2010, 1:09:39 PM10/14/10
to Clojure
On Oct 14, 11:54 am, Henk <henkp...@gmail.com> wrote:
> (I did some small benchmarks on this), while the list comprehension
> itself is much faster than python...

Not an answer to your question, but: depending on what you mean by
"much faster", there is a good chance that you measured the clojure
for expression doing nothing. You should wrap it in a doall or dorun
to get a proper timing (like a generator in Python).

Eg: for me, the following are almost exactly the same speed (~45ms):

user=> (time (dorun (for [i (range 100000)] [i (* i i)])))
"Elapsed time: 45.965679 msecs"

C:\Users\chris>python -m timeit "[(i,i*i) for i in range(100000)]"
10 loops, best of 3: 45.5 msec per loop


- Chris

Henk

unread,
Oct 14, 2010, 4:54:06 PM10/14/10
to Clojure
Thanx!,

That is exactly what I was looking for!,

Being a clojure newbie and a non-native speaker it is hard to find
the correct function among many in clojure core API :-)
If only the documentation would provide simple examples like you
provided...

Henk

unread,
Oct 14, 2010, 5:07:05 PM10/14/10
to Clojure
Does dotimes force evaluation?,
if so, then the Clojure version is about twice as fast for me...
which would be nice to finally find a good dynamic programming
language that is also
nice and fast :-)


the code I tested is this:

(def HHQ [{:id 1956, :firstname "Piet", :lastname
"Puk", :programming_skills #{:java, :php, :closure}}
{:id 2000, :firstname "Blaat", :lastname
"Aap", :programming_skills #{:java, :php, :python}}
{:id 2020, :firstname "Jaap", :lastname
"Klaas", :programming_skills #{:cobol, :php, :skala}}])

(time
(dotimes [n 1000000]
(into {} (for [x HHQ :when ((x :programming_skills) :java)]
[(x :id) (str (x :firstname) " " (x :lastname))]))))

vs the python version

HHQ = [{'id': 1956, 'firstname': "Piet", 'lastname': "Puk",
'programming_skills': set(['java', 'php', 'closure'])},
{'id': 2000, 'firstname': "Blaat", 'lastname': "Aap",
'programming_skills': set(['java', 'php', 'python'])},
{'id': 2020, 'firstname': "Jaap", 'lastname': "Klaas",
'programming_skills': set(['cobol', 'php', 'skala'])}]

import time
start = time.time()
for i in range(1000000):
dict([(x['id'], (x['firstname'] + " " + x['lastname'])) for x in HHQ
if 'java' in x['programming_skills']])
end = time.time()

print end - start

David Nolen

unread,
Oct 14, 2010, 5:18:04 PM10/14/10
to clo...@googlegroups.com
On Thu, Oct 14, 2010 at 4:54 PM, Henk <henk...@gmail.com> wrote:
Thanx!,

That is exactly what I was looking for!,

Being a clojure newbie and a non-native speaker it is hard to find
the correct function among many in clojure core API :-)
If only the documentation would provide simple examples like you
provided...

Growing list of examples here, http://clojuredocs.org. Also the IRC channel's a great to pick up knowledge.

David 

Meikel Brandmeyer

unread,
Oct 14, 2010, 6:34:59 PM10/14/10
to clo...@googlegroups.com
Hi,

Am 14.10.2010 um 23:07 schrieb Henk:

> Does dotimes force evaluation?,

At a different level. (dotimes [n 10000] (for ...)) does evaluate the for form. But it returns a seq which is never realised. So you do effectively … nothing. (dotimes [n 10000] (into [] (for ...))) as in your example does consume the sequence and hence realises it. So all the work defined in the for form is actually done. However this is do to into being eager and has nothing to do with dotimes.

Sincerely
Meikel


Alan

unread,
Oct 14, 2010, 7:24:09 PM10/14/10
to Clojure
I wouldn't say it has *nothing* to do with dotimes. If dotimes were
lazy rather than eager, then his form would do nothing despite the
eagerness of into, because into is not being called:

(for [i (range 1000000)]
(into [] (some-expensive-calc)))
Reply all
Reply to author
Forward
0 new messages