if / else en una lista de comprensión

Respuestas:

1461

Puedes hacer eso totalmente. Es solo un problema de pedido:

[unicode(x.strip()) if x is not None else '' for x in row]

En general,

[f(x) if condition else g(x) for x in sequence]

Y, solo para las comprensiones de listas con ifcondiciones,

[f(x) for x in sequence if condition]

Tenga en cuenta que esto realmente usa una construcción de lenguaje diferente, una expresión condicional , que en sí misma no es parte de la sintaxis de comprensión , mientras que ifdespués for…ines parte de las comprensiones de listas y se usa para filtrar elementos de la fuente iterable.


Las expresiones condicionales se pueden usar en todo tipo de situaciones en las que desee elegir entre dos valores de expresión en función de alguna condición. Esto hace lo mismo que el operador ternario ?:que existe en otros idiomas . Por ejemplo:

value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')
dar un toque
fuente
141
Tenga en cuenta que el if / else aquí es ahora la sintaxis de "operador ternario" y no la sintaxis de comprensión de la lista.
Adam Vandenberg el
8
Es por eso que prefiero poner el operador ternario entre paréntesis, deja en claro que es solo una expresión normal, no una comprensión.
Jochen Ritzel el
17
Entonces, el truco es "En la compresión de listas escribo si antes para entonces también tengo que agregar otra parte". porque si mi l = [ 2, 3, 4, 5]entonces [x if x % 2 == 0 for x in l]me da error mientras [x if x % 2 == 0 else 200 for x in l]funciona. Sí, sé filtrarlo, debo escribir [ x for x in l if x % 2 == 0]. Perdón por la molestia. Gracias por tu respuesta.
Grijesh Chauhan
55
Los documentos de Python mencionan el operador ternario . Tenga en cuenta que requiere lo contrario, o no funciona.
naugh101
44
Las comprensiones de @Drewdin List no admiten interrupciones durante su iteración. Tendrás que usar un bucle normal entonces.
Poke
44

De una sola mano:

def change(f):
    if f is None:
        return unicode(f.strip())
    else:
        return ''

row = [change(x) for x in row]

Aunque entonces tienes:

row = map(change, row)

O puede usar una lambda en línea.

Adam Vandenberg
fuente
13
Esta también es una buena (tal vez solo) técnica para usar cuando tiene que manejar posibles excepciones de la ifexpresión o el código en su elsebloque de instrucciones. La respuesta aceptada es mejor para casos simples.
Martineau
37

Aquí hay otro ejemplo ilustrativo:

>>> print(", ".join(["ha" if i else "Ha" for i in range(3)]) + "!")
Ha, ha, ha!

Explota el hecho de que if ievalúa Falsepara 0y Truepara todos los demás valores generados por la función range(). Por lo tanto, la comprensión de la lista se evalúa de la siguiente manera:

>>> ["ha" if i else "Ha" for i in range(3)]
['Ha', 'ha', 'ha']
Bengt
fuente
37

El problema específico ya se ha resuelto en respuestas anteriores, por lo que abordaré la idea general de usar condicionales dentro de las comprensiones de listas.

Aquí hay un ejemplo que muestra cómo se pueden escribir los condicionales dentro de una comprensión de lista:

X = [1.5, 2.3, 4.4, 5.4, 'n', 1.5, 5.1, 'a']     # Original list

# Extract non-strings from X to new list
X_non_str = [el for el in X if not isinstance(el, str)]  # When using only 'if', put 'for' in the beginning

# Change all strings in X to 'b', preserve everything else as is
X_str_changed = ['b' if isinstance(el, str) else el for el in X]  # When using 'if' and 'else', put 'for' in the end

Tenga en cuenta que en la primera lista de comprensión X_non_str, el orden es:

expresión para elemento en iterable si condición

y en la última lista de comprensión para X_str_changed, el orden es:

expresión1 si la condición más expresión2 para el elemento en iterable

Siempre me resulta difícil recordar que expresseion1 tiene que estar antes si if y expresión2 tiene que estar después de else . Mi cabeza quiere que ambos sean antes o después.

Supongo que está diseñado así porque se parece al lenguaje normal, por ejemplo, "Quiero quedarme adentro si llueve, de lo contrario quiero salir"

En inglés simple, los dos tipos de comprensiones de listas mencionadas anteriormente podrían expresarse como:

Con solo if:

extract_apple para apple en box_of_apples si apple_is_ripe

y con if/else

mark_apple si apple_is_ripe demás leave_it_unmarked de manzana en box_of_apples

Tim Skov Jacobsen
fuente
7

Las otras soluciones son excelentes para una sola if/ elseconstrucción. Sin embargo, las declaraciones ternarias dentro de las comprensiones de listas son posiblemente difíciles de leer.

El uso de una función ayuda a la legibilidad, pero tal solución es difícil de extender o adaptar en un flujo de trabajo donde el mapeo es una entrada. Un diccionario puede aliviar estas preocupaciones:

row = [None, 'This', 'is', 'a', 'filler', 'test', 'string', None]

d = {None: '', 'filler': 'manipulated'}

res = [d.get(x, x) for x in row]

print(res)

['', 'This', 'is', 'a', 'manipulated', 'test', 'string', '']
jpp
fuente
1

Tiene que ver con cómo se realiza la comprensión de la lista.

Tenga en cuenta lo siguiente:

[ expression for item in list if conditional ]

Es equivalente a:

for item in list:
    if conditional:
        expression

Donde el expressionestá en un formato ligeramente diferente (piense en cambiar el tema y el orden verbal en una oración)

Por lo tanto, su código [x+1 for x in l if x >= 45]hace esto:

for x in l:
    if x >= 45:
        x+1

Sin embargo, este código [x+1 if x >= 45 else x+5 for x in l]hace esto (después de reorganizar expression):

for x in l:
    if x>=45: x+1
    else: x+5
arboc7
fuente
0

No hay necesidad de ternary if / then / else. En mi opinión, su pregunta requiere esta respuesta:

row = [unicode((x or '').strip()) for x in row]
mariotomo
fuente
0

Haga una lista de elementos en un iterable

Parece mejor generalizar primero todas las formas posibles en lugar de dar respuestas específicas a las preguntas. De lo contrario, el lector no sabrá cómo se determinó la respuesta. Aquí hay algunas formas generalizadas que pensé antes de que me doliera la cabeza tratando de decidir si una cláusula final podría usarse en la última forma.

[expression1(item)                                        for item in iterable]

[expression1(item) if conditional1                        for item in iterable]

[expression1(item) if conditional1 else expression2(item) for item in iterable]

[expression1(item) if conditional1 else expression2(item) for item in iterable if conditional2]

El valor de itemno necesita ser usado en ninguna de las cláusulas condicionales. A conditional3puede usarse como un interruptor para agregar o no agregar un valor a la lista de salida.

Por ejemplo, para crear una nueva lista que elimine cadenas vacías o espacios en blanco de la lista original de cadenas:

newlist = [s for s in firstlist if s.strip()]
Hewey Dewey
fuente
1
El segundo da un error cuando Tim respondió en su comentario, vea también las declaraciones condicionales en los documentos de Python. Que son bastante ilegibles para mí. Resumen: solo this if condition else thato se permite una expresión normal. No value = this if condition(que se puede lograr con value = this if condition else None)
Anderium
0

Puedes combinar la lógica condicional en una comprensión:

 ps = PorterStemmer()
 stop_words_english = stopwords.words('english')
 best = sorted(word_scores.items(), key=lambda x: x[1], reverse=True)[:10000]
 bestwords = set([w for w, s in best])


 def best_word_feats(words):
   return dict([(word, True) for word in words if word in bestwords])

 # with stemmer
 def best_word_feats_stem(words):
   return dict([(ps.stem(word), True) for word in words if word in bestwords])

 # with stemmer and not stopwords
 def best_word_feats_stem_stop(words):
   return dict([(ps.stem(word), True) for word in words if word in bestwords and word not in stop_words_english])
Max Kleiner
fuente
-2
# coding=utf-8

def my_function_get_list():
    my_list = [0, 1, 2, 3, 4, 5]

    # You may use map() to convert each item in the list to a string, 
    # and then join them to print my_list

    print("Affichage de my_list [{0}]".format(', '.join(map(str, my_list))))

    return my_list


my_result_list = [
   (
       number_in_my_list + 4,  # Condition is False : append number_in_my_list + 4 in my_result_list
       number_in_my_list * 2  # Condition is True : append number_in_my_list * 2 in my_result_list
   )

   [number_in_my_list % 2 == 0]  # [Condition] If the number in my list is even

   for number_in_my_list in my_function_get_list()  # For each number in my list
]

print("Affichage de my_result_list [{0}]".format(', '.join(map(str, my_result_list))))

(venv) $ python list_comp.py
Affichage de my_list [0, 1, 2, 3, 4, 5]
Affichage de my_result_list [0, 5, 4, 7, 8, 9]

Entonces, para ti: row = [('', unicode(x.strip()))[x is not None] for x in row]

Trop Freshloïc
fuente
¿Qué significa "Affichage de ..." ? ¿Es francés?
Peter Mortensen