viernes, 6 de junio de 2008

List Comprehension

(Material de un Taller que hicimos en la pega)

List Comprehension
==================
List comprehensions provide a concise way to create lists without resorting to use of map(), filter() and/or lambda. The resulting list definition tends often to be clearer than lists built using those constructs. Each list comprehension consists of an expression followed by a for clause, then zero or more for or if clauses. The result will be a list resulting from evaluating the expression in the context of the for and if clauses which follow it. If the expression would evaluate to a tuple, it must be parenthesized.

Simples
=======
>>> [x for x in [1,3,5,7,9]]
[1, 3, 5, 7, 9]

>>> [x for x in range(5)]
[0, 1, 2, 3, 4]

>>> [x for x in range(2,10,2)]
[2, 4, 6, 8]

También se pueden anidar varios ciclos for (Gracias Dorian!)

>>> [ (x,y) for x in [1,2,3] for y in [4,5,6]]
[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]

Strings funcionan como listas
=============================
>>> [x for x in "Hola compadre"]
['H', 'o', 'l', 'a', ' ', 'c', 'o', 'm', 'p', 'a', 'd', 'r', 'e']



Cálculos:
=========
>>> [x*x for x in range(5)]
[0, 1, 4, 9, 16]


Condiciones:
============
>>> [x*x for x in range(5) if x%2]
[1, 9]
>>> [x*x for x in range(6) if x>3]
[16, 25]


Parseo de archivos:
===================
>>> stream="""Nombre, calorias, cantidad
... perejil, 10, 5
... betarraga, 20, 2
... zanahoria, 30, 10
... chocolate, 1000, 1"""
>>> [line.split(',') for line in stream.split('\n')[1:]]
[['perejil', ' 10', ' 5'], ['betarraga', ' 20', ' 2'], ['zanahoria', ' 30', ' 10'], ['chocolate', ' 1000', ' 1']]

>>> [[e.strip() for e in line.split(',')] for line in stream.split('\n')[1:]]
[['perejil', '10', '5'], ['betarraga', '20', '2'], ['zanahoria', '30', '10'], ['chocolate', '1000', '1']]

>>> [ "Nombre: %s, calorias: %s, cantidad: %s" % tuple([e.strip() for e in line.split(',')]) for line in stream.split('\n')[1:]]
['Nombre: perejil, calorias: 10, cantidad: 5', 'Nombre: betarraga, calorias: 20, cantidad: 2', 'Nombre: zanahoria, calorias: 30, cantidad: 10', 'Nombre: chocolate, calorias: 1000, cantidad: 1']


Capturar solo los números
=========================
>>> values = [[e.strip() for e in line.split(',')] for line in stream.split('\n')[1:]]
>> [ [int(v) for v in line if v.isdigit()] for line in values]
[[10, 5], [20, 2], [30, 10], [1000, 1]]


Pasar los valores formateados
=============================
>>> values_formated = [ ( l[0],int(l[1]),int(l[2]) ) for l in values]
>>> [line for line in values_formated if line[2]>2]
[('perejil', 10, 5), ('zanahoria', 30, 10)]


Suma condicionada: Sumar calorias de todos los elementos con cantidad>2
============================================
>>> sum( [line[1] for line in values_formated if line[2]>2] )
40


Construir strings usando List comprehension
===========================================
Ejemplo para armar una SQL que haga union de varias tablas
>>> " UNION ".join(
... ['SELECT max(%s) as time FROM "%s".%s' % tuple(x[:1]+['SCHEMA_NAME']+x[1:])
... for x in [
... ['field1','table1'],
... ['field2','table2'],
... ['field3','table3'],
... ['field4','table4']
... ]
... ]
... )
'SELECT max(field1) as time FROM "SCHEMA_NAME".table1 UNION SELECT max(field2) as time FROM "SCHEMA_NAME".table2 UNION SELECT max(field3) as time FROM "SCHEMA_NAME".table3 UNION SELECT max(field4) as time FROM "SCHEMA_NAME".table4'



Creación de Dictionary
======================
Ejemplo:
========
Esto no es necesario hacerlo:
d={}
for row in rows:
if d.has_key(row[0]):
d[row[0]].append((row[1], row[2]))
else:
d[row[0]] = [(row[1], row[2])]

Basta con hacer:

>>> rows=[[1,2,3,4,5],[6,7,8,9,0],[11,12,13,14,15]]
>>> d={}
>>> d.update( [ (r[0],(r[1],r[2])) for r in rows] )
>>> d
{1: (2, 3), 11: (12, 13), 6: (7, 8)}



Interseccion, Union, Diferencia entre listas
============================================
>>> A=[1,2,3,4,5]
>>> B=[2,4,6,8]
# Intersecion
>>> [x for x in A if x in B]
[2, 4]
>>> [x for x in B if x in A]
[2, 4]
# Difference
>>> [x for x in B if x not in A]
[6, 8]
>>> [x for x in A if x not in B]
[1, 3, 5]
>>>

Otra forma usando Set
=====================
>>> set(A).intersection(B)
set([2, 4])
>>> list(set(A).intersection(B))
[2, 4]
>>> list(set(B).intersection(A))
[2, 4]
>>> list(set(B).difference(A))
[8, 6]
>>> list(set(A).difference(B))
[1, 3, 5]


Set:
====
A set object is an unordered collection of distinct hashable objects. Common uses include membership testing, removing duplicates from a sequence, and computing mathematical operations such as intersection, union, difference, and symmetric difference. New in version 2.4.


Desafío:
=========

¿Se puede hacer esto con list comprehension?
¿si? ¿no? ¿porqué? ¿cómo?
>>> l=[]
>>> for n in ['Francisco','Richard', 'Luis']:
... for c in ['Fruta','Carne','Verdura']:
... if not(n=='Luis' and c=='Carne'):
... l.append('%s come %s' % (n,c))
...
>>> l
['Francisco come Fruta', 'Francisco come Carne', 'Francisco come Verdura', 'Richard come Fruta', 'Richard come Carne', 'Richard come Verdura', 'Luis come Fruta', 'Luis come Verdura']

No hay comentarios: