PyNEwbie
PyNEwbie

Reputation: 4950

Is there a better way to convert a list to a dictionary in Python with keys but no values?

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 is there a better way to do this?

Upvotes: 6

Views: 1357

Answers (6)

Markon
Markon

Reputation: 4610

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

Upvotes: 1

RexE
RexE

Reputation: 17733

You can use a list comprehension:

my_list = ['a','b','c','d']
my_dict = dict([(ele, None) for ele in my_list])

Upvotes: 1

Alex Martelli
Alex Martelli

Reputation: 882421

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!-)

Upvotes: 5

Mark Rushakoff
Mark Rushakoff

Reputation: 258388

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}

Upvotes: 1

Greg Hewgill
Greg Hewgill

Reputation: 994231

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.

Upvotes: 15

Ayman Hourieh
Ayman Hourieh

Reputation: 137336

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.

Upvotes: 23

Related Questions