2010-05-23 14 views
14

Una de las principales fortalezas de python y algunos otros lenguajes de programación (funcionales) son los list comprehension. Permiten a los programadores escribir expresiones complejas en 1 línea. Pueden ser confusos al principio, pero si uno se acostumbra a la sintaxis, es mucho mejor que anidar complicado para bucles.Muéstrame algunas comprensiones geniales de la lista de Python

Dicho esto, por favor comparta conmigo algunos de los mejores usos de la lista de comprensiones. (Por genial, solo quiero decir útil) Podría ser para algún concurso de programación, o un sistema de producción.

Por ejemplo: para hacer la traspuesta de una matriz mat

>>> mat = [ 
...  [1, 2, 3], 
...  [4, 5, 6], 
...  [7, 8, 9], 
...  ] 

>>> [[row[i] for row in mat] for i in [0, 1, 2]] 
[[1, 4, 7], [2, 5, 8], [3, 6, 9]] 

Por favor, incluir una descripción de la expresión y donde fue utilizado (si es posible).

+2

Debe marcar esto como wiki de la comunidad (edite su pregunta y marque la casilla). –

+1

Tenga en cuenta que si está representando matrices, probablemente desee utilizar 'numpy'. –

+4

Para una transposición más ágil de 'mat', intente' zip (* mat) '. – PaulMcG

Respuesta

8

Para hacer la transpuesta de una matriz mat:

>>> [list(row) for row in zip(*mat)] 
[[1, 4, 7], [2, 5, 8], [3, 6, 9]] 
+3

'map (list, zip (* mat))' es un poco terser (aunque no es una lista de comprensión). – Grumdrig

+1

Terse es negativo, no positivo. En primer lugar, evitar map() es uno de los principales beneficios de las listas de comprensión. –

+7

@Glenn Esa es una generalización terriblemente amplia. Dado que las comprensiones son una forma más fácil de expresar bucles, si la concisión es siempre mala, siempre debe expandirlos en bucles. –

7

para aplanar una lista de listas:

>>> matrix = [[1,2,3], [4,5,6]] 
>>> [x for row in matrix for x in row] 
[1, 2, 3, 4, 5, 6] 
+4

O simplemente suma (matriz, []). :) –

+0

@Nick, oh mierda - buen punto. – Grumdrig

+0

Solo tenga en cuenta que la versión de la lista de comprensión es mucho más eficiente para listas grandes que suma (matriz, []). – David

16

Mucha gente no sabe que Python le permite filtrar los resultados de una lista por comprensión usando if:

>>> [i for i in range(10) if i % 2 == 0] 
[0, 2, 4, 6, 8] 
4

utilizo todo el tiempo al cargar archivos separados por tabuladores con líneas de comentarios opcionales que comienzan con un signo de número:

data = [line.strip().split("\t") for line in open("my_file.tab") \ 
     if not line.startswith('#')] 

Por supuesto que funciona para cualquier otro comentario y el separador de carácter también.

+0

Esto es horrible. No aplaste muchos códigos en una lista comprensiva: divida esto. –

+0

@Glenn Maynard: De acuerdo. Las comprensiones de listas no están pensadas para ser usadas de esa forma, y ​​de todos modos, se frustra el propósito de iterar archivos por líneas porque simplemente se está leyendo todo al mismo tiempo y usando una lista de comprensión para realizar trabajos en la línea. No solo eso, sino ... ¿cuándo se cierra el archivo? Si bien me doy cuenta de la ventaja de tal comprensión, también hay desventajas, así que ten cuidado. Eso es casi tan malo como una llamada a 'malloc' en C sin una llamada correspondiente a' free' o 'new' sin un' delete' complementario en C++.> _ < – Dustin

+6

No estoy de acuerdo con que esto sea horrible. Creo que es bastante legible y más o menos legible que la versión de línea múltiple. – Grumdrig

2

Mientras esté buscando programación funcional inspirada en partes de Python, considere mapa, filtro, reducción y zip ---- todo ofrecido en python.

+1

Explicación de Guido de por qué las listas de comprensión generalmente tienen más sentido que el mapa/filtro: http://www.artima.com/weblogs/viewpost.jsp?thread=98196 –

3

Actualmente tengo varios scripts que necesitan agrupar un conjunto de puntos en "niveles" por altura. La suposición es que los valores z de los puntos se agruparán sin apretar alrededor de ciertos valores correspondientes a los niveles, con espacios grandes entre los grupos.

Así que tienen la siguiente función:

def level_boundaries(zvalues, threshold=10.0): 
    '''Finds all elements z of zvalues such that no other element 
    w of zvalues satisfies z <= w < z+threshold.''' 
    zvals = zvalues[:] 
    zvals.sort() 
    return [zvals[i] for i, (a, b) in enumerate(pairs(zvals)) if b-a >= threshold] 

"pares" se toma directamente de la documentación del módulo itertools, pero para referencia:

def pairs(iterable): 
    'iterable -> (iterable[n], iterable[n+1]) for n=0, 1, 2, ...' 
    from itertools import izip, tee 
    first, second = tee(iterable) 
    second.next() 
    return izip(first, second) 

Un ejemplo de uso artificial (mis conjuntos de datos reales son bastante grandes para usar como ejemplos):

>>> import random 
>>> z_vals = [100 + random.uniform(-1.5,1.5) for n in range(10)] 
>>> z_vals += [120 + random.uniform(-1.5,1.5) for n in range(10)] 
>>> z_vals += [140 + random.uniform(-1.5,1.5) for n in range(10)] 
>>> random.shuffle(z_vals) 
>>> z_vals 
[141.33225473458657, 121.1713952666894, 119.40476193163271, 121.09926601186737, 119.63057973814858, 100.09095882968982, 99.226542624083109, 98.845285642062763, 120.90864911044898, 118.65196386994897, 98.902094334035326, 121.2741094217216, 101.18463497862281, 138.93502941970601, 120.71184773326806, 139.15404600347946, 139.56377827641663, 119.28279815624718, 99.338144106822554, 139.05438770927282, 138.95405784704622, 119.54614935118973, 139.9354467277665, 139.47260445000273, 100.02478729763811, 101.34605205591622, 138.97315450408186, 99.186025111246295, 140.53885845445572, 99.893009827114568] 
>>> level_boundaries(z_vals) 
[101.34605205591622, 121.2741094217216] 
+0

¿Podría mostrar la posible importación de valores z? – christangrant

+0

He agregado un ejemplo, si eso es lo que quería decir. –

9

A menudo uso intel hensions para construir predice:

my_dict = dict((k, some_func(k)) for k in input_list) 

Nota Python 3 tiene por comprensión de diccionario, por lo que este se convierte en:

my_dict = {k:some_func(k) for k in input_list} 

Para la construcción de los datos CSV, como de una lista de tuplas:

data = "\n".join(",".join(x) for x in input) 
No

en realidad una lista de comprensión, pero sigue siendo útil: Produzca una lista de rangos de una lista de 'puntos de corte':

ranges = zip(cuts, cuts[1:]) 
+0

Ninguno de ellos es una lista de comprensión. Esas son expresiones de generador. –

+0

Una lista de comprensión es simplemente un caso especial de un genexp, sin embargo. Puedo ponerles corchetes si eso te hace feliz, pero supongo que a OP le interesaba la técnica, no los detalles. –

5

Si "fresco" significa loco, como este:

def cointoss(n,t): 
    return (lambda a:"\n".join(str(i)+":\t"+"*"*a.count(i) for i in range(min(a),max(a)+1)))([sum(randint(0,1) for _ in range(n)) for __ in range(t)]) 

>>> print cointoss(20,100) 
3: ** 
4: *** 
5: ** 
6: ***** 
7: ******* 
8: ********* 
9: ********* 
10: ******************** 
11: ***************** 
12: ********* 
13: ***** 
14: ********* 
15: * 
16: ** 

n y t controlar el número de lanzamientos de moneda por prueba y el número de veces que se ejecuta la prueba y la distribución se representa.

Cuestiones relacionadas