views:

91

answers:

5

I have a list of strings parsed from somewhere, in the following format:

[key1, value1, key2, value2, key3, value3, ...]

I'd like to create a dictionary based on this list, like so:

{key1:value1, key2:value2, key3:value3, ...}

An ordinary for loop with index offsets would probably do the trick, but I wonder if there's a Pythonic way of doing this. List comprehensions seem interesting, but I can't seem to find out how to apply them to this particular problem.

Any ideas?

+10  A: 

You can try:

dict(zip(l[::2], l[1::2]))

Explanation: we split the list into two lists, one of the even and one of the odd elements, by taking them by steps of two starting from either the first or the second element (that's the l[::2] and l[1::2]). Then we use the zip builtin to the two lists into one list of pairs. Finally, we call dict to create a dictionary from these key-value pairs.

This is ~4n in time and ~4n in space, including the final dictionary. It is probably faster than a loop, though, since the zip, dict, and slicing operators are written in C.

pavpanchekha
Exactly what I needed and nicely explained, thanks a lot pavpanchekha!
KennyDeriemaeker
A: 
result = dict(grouper(2, L))

grouper is a function that forms pairs in a list, it's given in the itertools receipes:

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

dict takes a list of (key,value) pairs and makes a dict from them.

You could also write result = dict(zip(*[iter(L)]*2)) and confuse most readers :-)

THC4k
`result = dict(zip(*[iter(L)]*2))` isn't guaranteed to work (zip makes no guarantees about the order of evaluation of its arguments). You should use `result = dict(izip(*[iter(L)]*2))` instead as in addition to being a model of clarity(!) that does guarantee the correct order of evaluation.
Duncan
@Ducan: Where did you get that (wrong) idea? See http://docs.python.org/library/functions.html#zip `izip` is just the iterator version of `zip`.
THC4k
+1  A: 
In [71]: alist=['key1', 'value1', 'key2', 'value2', 'key3', 'value3']

In [72]: dict(alist[i:i+2] for i in range(0,len(alist),2))
Out[72]: {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
unutbu
+1  A: 

In addition to pavpanchekha's short and perfectly fine solution, you could use a generator expression (a list comprehensions is just a generator expression fed to the list constructor - it's actually more powerful und universal) for extra goodness:

dict((l[i], l[l+1]) for i in range(0, len(l)-1, 2))

Apart from being really cool and functional, it's also a better algorithm: Unless the implementation of dict is especially stupid (unlikely considered it's a built-in), this will consume the same amount of memory for every size of l (i.e. runs in constant aka O(1) space) since it processes one pair at a time instead of creating a whole new list of tuples first.

delnan
+2  A: 

A nice opportunity to display my favorite python idiom:

>>> S = [1,2,3,4,5,6]
>>> dict(zip(*[iter(S)]*2))
{1: 2, 3: 4, 5: 6}

That tricky line passes two arguments to zip() where each argument is the same iterator over S. zip() creates 2-item tuples, pulling from the iterator over zip each time. dict() then converts those tuples to a dictionary.

To extrapolate:

S = [1,2,3,4,5,6]

I = iter(S)
dict(zip(I,I))
Triptych
That's AWESOME. Major brownie points!
katrielalex