views:

295

answers:

6

I was sure that there would be a one liner to convert a list to a dictionary where the items in the list were keys and the dictionary had no values.

The only way I could find to do it was argued against

"Using list comprehensions when the result is ignored is misleading and inefficient. A for loop is better"

myList=['a','b','c','d']
myDict={}
x=[myDict.update({item:None}) for item in myList]

>>> myDict
{'a': None, 'c': None, 'b': None, 'd': None}

It works but I thought someone might have some insight as to a better way to do this.

+19  A: 

Use dict.fromkeys:

>>> my_list = [1, 2, 3]
>>> dict.fromkeys(my_list)
{1: None, 2: None, 3: None}

Values default to None, but you can specify them as an optional argument:

>>> my_list = [1, 2, 3]
>>> dict.fromkeys(my_list, 0)
{1: 0, 2: 0, 3: 0}

From the docs:

a.fromkeys(seq[, value]) Creates a new dictionary with keys from seq and values set to value.

dict.fromkeys is a class method that returns a new dictionary. value defaults to None. New in version 2.3.

Ayman Hourieh
+1, beat me. :)
Paolo Bergantino
Thanks this was helpful
PyNEwbie
+13  A: 

You could use a set instead of a dict:

>>> myList=['a','b','c','d']
>>> set(myList)
set(['a', 'c', 'b', 'd'])

This is better if you never need to store values, and are just storing an unordered collection of unique items.

Greg Hewgill
+1  A: 

And here's a fairly wrong and inefficient way to do it using map:

>>> d = dict()
>>> map (lambda x: d.__setitem__(x, None), [1,2,3])
[None, None, None]
>>> d
{1: None, 2: None, 3: None}
Mark Rushakoff
+5  A: 

To answer the original questioner's performance worries (for lookups in dict vs set), somewhat surprisingly, dict lookups can be minutely faster (in Python 2.5.1 on my rather slow laptop) assuming for example that half the lookups fail and half succeed. Here's how one goes about finding out:

$ python -mtimeit -s'k=dict.fromkeys(range(99))' '5 in k and 112 in k'
1000000 loops, best of 3: 0.236 usec per loop
$ python -mtimeit -s'k=set(range(99))' '5 in k and 112 in k'
1000000 loops, best of 3: 0.265 usec per loop

doing each check several times to verify they're repeatable. So, if those 30 nanoseconds or less on a slow laptop are in an absolutely crucial bottleneck, it may be worth going for the obscure dict.fromkeys solution rather than the simple, obvious, readable, and clearly correct set (unusual -- almost invariably in Python the simple and direct solution has performance advantages too).

Of course, one needs to check with one's own Python version, machine, data, and ratio of successful vs failing tests, and confirm with extremely accurate profiling that shaving 30 nanoseconds (or whatever) off this lookup will make an important difference.

Fortunately, in the vast majority of cases, this will prove totally unnecessary... but since programmers will obsess about meaningless micro-optimizations anyway, no matter how many times they're told about their irrelevance, the timeit module is right there in the standard library to make those mostly-meaningless micro-benchmarks easy as pie anyway!-)

Alex Martelli
This is an awesome comment. Every developer obsesses with micro-optimizations must be made to read it over and over again. Reminds me of "(unrolling of far loop, for better performance)[http://www.reddit.com/r/programming/comments/8ozon/how_to_write_unmaintainable_code_a_stepbystep/c09zh2a]"
Lakshman Prasad
+1  A: 

You can use a list comprehension:

my_list = ['a','b','c','d']
my_dict = dict([(ele, None) for ele in my_list])
RexE
You can also use a generator comprehension (just drop the square brackets!)In Python 3.0, there are even dict comprehensions
Rick Copeland
A: 

Maybe you can use itertools:

>>>import itertools
>>>my_list = ['a','b','c','d']
>>>d = {}
>>>for x in itertools.imap(d.setdefault, my_list): pass
>>>print d
{'a': None, 'c': None, 'b': None, 'd': None}

For huge lists, maybe this is very good :P

Markon
Tip: highlight your code and press ctrl-k to get syntax highlighting and preserve proper indentation.
Adam Bernier
thank you very much ;)
Markon