tags:

views:

151

answers:

5

I have a list which looks something like this

List = [q1,a1,q2,a2,q3,a3]

I need the final code to be something like this

dictionary = {q1:a1,q2:a2,q3:a3}

if only I can get values at a certain index e.g List[0] I can accomplish this, is there any way I can get it?

+9  A: 

Python dictionaries can be constructed using the dict class, given an iterable containing tuples. We can use this in conjunction with the range builtin to produce a collection of tuples as in (every-odd-item, every-even-item), and pass it to dict, such that the values organize themselves into key/value pairs in the final result:

dictionary = dict([(List[i], List[i+1]) for i in range(0, len(List), 2)])
zzzeek
You could take out the `[]` s to change the list comprehension to a generator for greater efficiency: `dict((List[i], List[i+1]) for i in range(0, len(List), 2))` That way, it won't generate a list only to later throw it away after it's converted to a dict.
Chris Lutz
You my friend are a life saver, God bless you. I have been on this for two hours
Fahim Akhter
OK now, the [] thing I left in first for py2.3 compatibility, *and* also the fact that I've heard the exact opposite - for very small collections, the list construction is faster than the overhead of constructing the generator. I can ask my colleague for more details on this one but it does make sense.
zzzeek
Ran into a wierd error. I have same values in the list for example [a,b,a,c,a,d] The output is unique values only e.g [a:b] How do I solve this?
Fahim Akhter
@zzzeek - For small lists it may be more efficient, but for large lists it will die. You can choose between overkill for smaller cases and massive performance penalties for larger cases. Which side would you prefer to be on?
Chris Lutz
@Fahim, in a dict each key has **one** value. Maybe you want to use a _list_ of one or more values per key? Worth a separate question!
Alex Martelli
yeah, for that issue you'd have a structure more like {key: set([v1,v2,v3])}. Ask a new question !
zzzeek
@Chris - I picked the side that works on Py2.3 :) Plus he's starting with a list so its unlikely to be a 30 meg collection.
zzzeek
I need to have a check on the key and after testing it decide to save the value or not. So now in the main loop I simply checked before saving it into the dictionary :D
Fahim Akhter
+9  A: 

Using extended slice notation:

dictionary = dict(zip(List[0::2], List[1::2]))
sth
that's really clever.
zzzeek
+3  A: 

The range-based answer is simpler, but there's another approach possible using the itertools package:

from itertools import izip
dictionary = dict(izip(*[iter(List)] * 2))

Breaking this down (edit: tested this time):

# Create instance of iterator wrapped around List
# which will consume items one at a time when called.
iter(List)

# Put reference to iterator into list and duplicate it so
# there are two references to the *same* iterator.
[iter(List)] * 2 

# Pass each item in the list as a separate argument to the
# izip() function.  This uses the special * syntax that takes
# a sequence and spreads it across a number of positional arguments.
izip(* [iter(List)] * 2)

# Use regular dict() constructor, same as in the answer by zzzeeek
dict(izip(* [iter(List)] * 2))

Edit: much thanks to Chris Lutz' sharp eyes for the double correction.

Peter Hansen
Typo in the last two lines: There's no ending `]`
Chris Lutz
Fixed typo pointed out by Chris (thanks!)
Peter Hansen
Now you put it in the wrong place. `iter(List) * 2` isn't valid methinks.
Chris Lutz
A: 

You've mentioned in the comments that you have duplicate entries. We can work with this. Take your favorite method of generating the list of tuples, and expand it into a for loop:

from itertools import izip

dictionary = {}
for k, v in izip(List[::2], List[1::2]):
    if k not in dictionary:
        dictionary[k] = set()
    dictionary[k].add(v)

Or we could use collections.defaultdict so we don't have to check if a key is already initialized:

from itertools import izip
from collections import defaultdict

dictionary = defaultdict(set)
for k, v in izip(List[::2], List[1::2]):
    dictionary[k].add(v)

We'll end with a dictionary where all the keys are sets, and the sets contain the values. This still may not be appropriate, because sets, like dictionaries, cannot hold duplicates, so if you need a single key to hold two of the same value, you'll need to change it to a tuple or a list. But this should get you started.

Chris Lutz
+2  A: 
d = {}
for i in range(0, len(List), 2):
    d[List[i]] = List[i+1]
inspectorG4dget
Thats exacts what I was thinking, the simplest and the best thing. :)
Fahim Akhter