Question

I have a list of values and I want to put them in a dictionary that would map each value to it's index.

I can do it this way:

>>> t = (5,6,7)
>>> d = dict(zip(t, range(len(t))))
>>> d
{5: 0, 6: 1, 7: 2}

this is not bad, but I'm looking for something more elegant.

I've come across the following, but it does the opposite of what I need:

>>> d = dict(enumerate(t))
>>> d
{0: 5, 1: 6, 2: 7}

Please share your solutions,
Thank you

EDIT: Python 2.6.4

For lists containing 1000 elements the dict(zip) version is the fastest, the generator and the list comprehension versions are virtually identical and they are ~1.5 times slower and the functional map(reversed) is considerably slower.

$ python -mtimeit -s"t = range(int(1e3))" "d = dict(zip(t, range(len(t))))"
1000 loops, best of 3: 277 usec per loop

$ python -mtimeit -s"t = range(int(1e3))" "d = dict([(y,x) for x,y in enumerate(t)])"
1000 loops, best of 3: 426 usec per loop

$ python -mtimeit -s"t = range(int(1e3))" "d = dict((y,x) for x,y in enumerate(t))"
1000 loops, best of 3: 437 usec per loop

$ python -mtimeit -s"t = range(int(1e3))" "d = dict(map(reversed, enumerate(t)))"
100 loops, best of 3: 3.66 msec per loop

I tried running the same tests for longer and for shorter lists (1e2, 1e4, 1e5) and the time per loop scales linearly with the length of the list.

Could somebody time py 2.7+ version?

Was it helpful?

Solution

You can use a list comprehension (or a generator, depending on your python version) to perform a simple in-place swap for your second example.


Using a list comprehension:

d = dict([(y,x) for x,y in enumerate(t)])

Using a generator expression (Python 2.4 and up):

d = dict((y,x) for x,y in enumerate(t))

OTHER TIPS

In Python2.7+ you can write it like this

>>> t = (5,6,7)
>>> d = {x:i for i,x in enumerate(t)}
>>> print d
{5: 0, 6: 1, 7: 2}
>>> dict((x,i) for i,x in enumerate(t))
{5: 0, 6: 1, 7: 2}
>>>

Are all your elements unique (i.e. your list would never be 5,6,7,7)? The dict solution will only work if all your elements are unique.

By storing the index, you're essentially duplicating information, since you could simply query the current index of the item in the list. Duplicating information is usually not the best idea, because it allows the possibility for one set of data to get out of sync with the other.

If the list is being modified, there's also nothing preventing you from accidentally assigning the same index to more than one item.

Why are you trying to store the index value, when you could simply get the index from the list?

As everybody has already written, in Python 2.6 I would consider the following as the most pythonic:

>>> dict((x, i) for i, x in enumerate(t))
{5: 0, 6: 1, 7: 2}

Still, in a moment of functional frenzy I would write:

>>> dict(map(reversed, enumerate(t)))
{5: 0, 6: 1, 7: 2}

I like the dict(zip(t, range(len(t)))) best.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top