2011-10-01 21 views
7

Tengo una lista y quiero usar una determinada función solo en aquellas entradas que cumplen una cierta condición, dejando las otras entradas sin modificar.Comprensión de la lista de Python - simple

Ejemplo: Supongamos que quiero multiplicar por 2 solo aquellos elementos que son pares.

a_list = [1, 2, 3, 4, 5] 

resultado deseado:

a_list => [1, 4, 3, 8, 5] 

Pero [elem * 2 for elem in a_list if elem %2 == 0] rendimientos [4, 8] (que actúan como un filtro, además).

¿Cuál es la forma correcta de hacerlo?

Respuesta

18

Utilice un conditional expression:

[x * 2 if x % 2 == 0 else x 
for x in a_list] 

(Nota del friki de la matemáticas: también se puede resolver este caso en particular con

[x * (2 - x % 2) for x in a_list] 

pero prefiero la primera opción de todos modos;)

+0

Gracias, esto funcionó muy bien. Además, gracias por las ediciones, intentaré usar el mismo formato a continuación. –

2
a_list = [1, 2, 3, 4, 5] 

print [elem*2 if elem%2==0 else elem for elem in a_list ] 

o, si tiene una lista muy larga que desea modificar en su lugar:

a_list = [1, 2, 3, 4, 5] 

for i,elem in enumerate(a_list): 
    if elem%2==0: 
     a_list[i] = elem*2 

así, sólo las incluso elementos se modifican

+0

¿No debería funcionar 'a_list [:] = list_comprehension' también para el reemplazo in situ? ¿Y eso sin tener que buclear en Python? – Voo

+0

@agf ¿Entonces crearía la nueva lista en otro lugar y luego actualizaría los elementos? Lástima, pensé que debido a las limitaciones de las listas de comprensión, podríamos garantizar que un elemento solo se pueda referenciar antes de que se sobrescriba para poder optimizarlo. – Voo

+0

@Voo La asignación in situ funciona desde cualquier iterable, por lo que podría hacerlo desde una expresión de generador. Acabo de probarlo, y eso parece funcionar incluso si usa 'reverseed (a_list)' o un generador que produce menos elementos que la longitud de la lista. No es algo que haya pensado hacer antes; gracias por traer la idea :). – agf

0

Usted podría utilizar lambda:

>>> a_list = [1, 2, 3, 4, 5] 
>>> f = lambda x: x%2 and x or x*2 
>>> a_list = [f(i) for i in a_list] 
>>> a_list 
[1, 4, 3, 8, 5] 

Editar - Pensando en observación agf 's hice una segunda versión de mi código:

>>> a_list = [1, 2, 3, 4, 5] 
>>> f = lambda x: x if x%2 else x*2 
>>> a_list = [f(i) for i in a_list] 
>>> a_list 
[1, 4, 3, 8, 5] 
+0

No use 'condition and true_value or false_value' para emular la operación ternaria; hay una versión realmente en Python. Además, no hay necesidad de envolverlo en una lambda de ninguna manera, ya que es una expresión en lugar de una afirmación, funciona bien en la lista de comprensión. 'lambda's tiene la misma limitación, por lo que no hay _necesita _ una necesidad en una lista de comprensión o expresión del generador. – agf

+0

@agf - Entiendo (y estoy de acuerdo) con su comentario sobre lambda, pero en este caso me parece una forma alternativa (aunque lejos de ser absolutamente perfecta) de poner en diferentes niveles la lógica de seleccionar elementos de la lista de comprensión . Y gracias por el resto sobre el operador ternario de Python. Hice una segunda versión para reflejar esto. –

+0

'lambda x:' y 'f()' tiene 12 caracteres, '[for i in a_list]' tiene 18, por lo que lo hace más claro y más rápido al tener la expresión en línea en lugar de 'lambda' solo seis caracteres más si tiene una lista completa de comprensión por separado en lugar de solo una función nueva. – agf

Cuestiones relacionadas