mercredi 13 octobre 2010

list comprehension

There is a way to write loops and test on lists in Python which is very condensate: the so-called list comprehension.
An example found in the French forum: http://www.developpez.net/forums/d962510/autres-langages/python-zope/general-python/operations-listes-dictionnaires/.
A guy wanted to transform a dictionary like this:
d= {'Ei': (1,3,4,4,6) , 'id' : ('r','r','t','t','t')}
into the list of occurence of each id:
[('r', [1, 3]), ('t', [4, 4, 6])]
One of the answers was:
L=[(d['id'][i],d['Ei'][i]) for i in xrange(0,len(d['Ei']))] 
R=[(x,[y[1] for y in L if y[0]==x]) for x in set(d['id']) ] 

Quite efficient!
The first step is to build a dictionary with the correspondances between the id and the Ei, the L:
[('r', 1), ('r', 3), ('t', 4), ('t', 4), ('t', 6)]
This is done with something like this:
In [8]: L2 = []
In [9]: for i in xrange(0,len(d['Ei'])):
   ...:     L2.append((d['id'][i],d['Ei'][i]))

Which can effectively be compacted as:
L=[(d['id'][i],d['Ei'][i]) for i in xrange(0,len(d['Ei']))] 
The second step (R) is the list comprehension form of the following, where we are counting the occurences of each id. First find the set of the different and uniq values of id: set() gives the solution.
Then looping on these values and find the occurences for each values. Finally put all this into a dictionary. The expand form would be:
R2=[]
uniqid = set(d['id'])
for x in uniqid:
    for y in L:
        if y[0]==x:
            R2.append([x,[y[1]]])
What can also be obtained like this:
R=[(x,[y[1] for y in L if y[0]==x]) for x in set(d['id']) ] 
This is more compact, in some sense more elegant, and I think more efficient (quicker), but not really sure of that...


Aucun commentaire:

Enregistrer un commentaire