si / si no en una lista de comprensión

1245

¿Cómo puedo hacer lo siguiente en Python?

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

Esencialmente:

  1. reemplace todos los Nones con cadenas vacías, y luego
  2. realizar una función.
1
2059

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, para listas comprensivas con ifcondiciones únicamente,

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

Tenga en cuenta que esto en realidad 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 del for…ines parte de las listas por comprensión y se usa para filtrar elementos de la fuente iterable.


Las expresiones condicionales se pueden utilizar 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')
13
  • 160
    Tenga en cuenta que el if / else aquí es ahora sintaxis de "operador ternario" y no sintaxis de comprensión de listas. Adam Vandenberg 23/11/10 a las 20:04
  • 8
    Por eso prefiero poner el operador ternario entre paréntesis, deja más claro que es solo una expresión normal, no una comprensión. Jochen Ritzel 23/11/10 a las 20:16
  • 20
    Entonces el truco es "En la compresión de la lista escribo si antes para entonces tengo que agregar otra parte también". porque si mi l = [ 2, 3, 4, 5]entonces [x if x % 2 == 0 for x in l]me da un error mientras que [x if x % 2 == 0 else 200 for x in l]funciona. Sí, sé que para filtrarlo debo escribir [ x for x in l if x % 2 == 0]. Perdón por las molestias. Gracias por tu respuesta. Grijesh Chauhan 29 de septiembre de 2013 a las 15:29
  • 7
    Los documentos de Python mencionan el operador ternario . Tenga en cuenta que requiere el else, o no funciona. naught101 7 de nov. De 2013 a las 23:23
  • 5
    @Drewdin Las comprensiones de la lista no admiten la ruptura durante su iteración. Entonces tendrás que usar un bucle normal. poke 16/03/15 a las 22:33
62

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

A continuación, se muestra un ejemplo que muestra cómo se pueden escribir condicionales dentro de una lista de comprensión:

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 comprensión de la lista X_non_str, el orden es:

expression for item in iterable if condition

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

expression1 if condition else expression2 for item in iterable

Siempre me resulta difícil recordar que expression1 tiene que estar antes de if y expression2 tiene que ser after 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 afuera".

En un lenguaje sencillo, los dos tipos de listas por comprensión mencionadas anteriormente podrían expresarse como:

Con solo if:

extract_apple for apple in apple_box if apple_is_ripe

y con if/else

mark_apple if apple_is_ripe else leave_it_unmarked for apple in apple_box

49

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.

1
  • 14
    Esta también es una buena (quizás la única) técnica para usar cuando tenga que manejar posibles excepciones de la ifexpresión o el código en su elsebloque de instrucciones o s. La respuesta aceptada es mejor para casos simples. martineau 23/11/10 a las 21:05
45

Aquí hay otro ejemplo ilustrativo:

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

Aprovecha 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']
0
9

Las otras soluciones son grandes para una sola if/ elseconstructo. Sin embargo, las declaraciones ternarias dentro de las listas por comprensión son posiblemente difíciles de leer.

El uso de una función ayuda a la legibilidad, pero dicha solución es difícil de ampliar 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', '']
0
5

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 expressionestá en un formato ligeramente diferente (piense en cambiar el orden de sujeto y verbo 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 el expression):

for x in l:
    if x>=45: x+1
    else: x+5
2

Make a list from items in an 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 al tratar de decidir si una cláusula else 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 tiene que ser utilizado en cualquiera de las cláusulas condicionales. A conditional3se puede usar 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 cadenas de espacios en blanco de la lista original de cadenas:

newlist = [s for s in firstlist if s.strip()]
1
  • 1
    El segundo da un error como respondió Tim 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 thatse permite una expresión normal o. No value = this if condition(que se puede lograr con value = this if condition else None)anderium 28 nov 2019 a las 9:03
2

Puedes hacerlo

row = [unicode(x.strip()) if x != None else '' for x in row]

Alguna sintaxis para la comprensión de listas:

[item if condition else item for item in items]
[f(item) if condition else value for item in items]
[item if condition for item in items]
[value if condition else value1 if condition1 else value2]
1
  • Esto parece un duplicado de la respuesta principal, con un poco de aclaración sobre las listas por comprensión. Brylie Christopher Oxley 26/08/20 a las 12:17
0

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

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

Puede 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])
0

Usemos esta pregunta para repasar algunos conceptos. Creo que es bueno ver primero los fundamentos para que pueda extrapolar a diferentes casos.

Otras respuestas proporcionan la respuesta específica a su pregunta. Primero daré un contexto general y luego responderé la pregunta.

Fundamentos

if/else Las declaraciones en las listas por comprensión implican dos cosas:

  • Lista de comprensiones
  • Expresiones condicionales (operadores ternarios)

1. Enumere las comprensiones

Ellos proporcionan una manera concisa para crear listas.

Su estructura consiste en: " corchetes que contienen una expresión seguida de una cláusula for, luego cero o más cláusulas for o if ".

Caso 1

Aquí no tenemos ninguna condición. Cada elemento del iterable se agrega a new_list.

new_list = [expression for item in iterable]
new_list = [x for x in range(1, 10)]
> [1, 2, 3, 4, 5, 6, 7, 8, 9]

Caso 2

Aquí tenemos una condición.

Ejemplo 1

Condición: solo se agregarán números paresnew_list .

new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0]
> [2, 4, 6, 8]

Ejemplo 2

Condición: solo se sumarán números pares que sean múltiplos de 3 new_list.

new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0 if x % 3 == 0]
> [6]

Pero, ¿cómo es posible que tengamos una condición si usamos dos ifen new_list?

La expresión anterior podría escribirse como:

new_list = [x for x in range(1, 10) if x % 2 and x % 3 == 0]
> [6]

Solo usamos una ifdeclaración.

Esto es como hacer:

new_list = []
for x in range(1, 10):
    if x % 2 == 0 and x % 3 == 0:
        new_list.append(x)
> [6]

Ejemplo 3

Solo por el bien de la discusión, también puede usar or.

Condición: se sumarán números pares o números múltiplos de 3 new_list.

new_list = [x for x in range(1, 10) if x % 2 == 0 or x % 3 == 0]
> [2, 3, 4, 6, 8, 9]

Caso 2

Más de una condición:

Aquí necesitamos la ayuda de expresiones condicionales (operadores ternarios).

2. Expresiones condicionales

¿Qué son las expresiones condicionales? Lo que dice el nombre: una expresión de Python que tiene alguna condición.

<Exp1> if condition else <Exp2>

Primero conditionse evalúa. Si conditiones True, entonces <Exp1>se evalúa y se devuelve. Si conditiones False, entonces <Exp2>se evalúa y se devuelve.

Una expresión condicional con más de una condición:

<Exp1> if condition else <Exp2> if condition else <Exp3>...    

Un ejemplo de Real Python :

age = 12
s = 'minor' if age < 21 else 'adult'
> minor

El valor de sestá condicionado al agevalor.

3.Enumere las comprensiones con condicionales

Juntamos listas comprensivas y condicionales de esta manera.

new_list = [<Conditional Expression> for <item> in <iterable>]

new_list = [<Exp1> if condition else <Exp2> if condition else <Exp3> for <item> in <iterable>]

Condición: los números pares se agregarán como 'even', el número tres se agregará como 'number three'y el resto se agregará como 'odd'.

new_list = ['even' if x % 2 == 0 else 'number three' if x == 3 else 'odd' 
             for x in range(1, 10)]
> ['odd', 'even', 'number three', 'even', 'odd', 'even', 'odd', 'even', 'odd']

La respuesta a la pregunta

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

Aquí tenemos un problema con la estructura de la lista: for x in rowdebería estar al final de la expresión.

Manera correcta:

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

Otras lecturas:

¿Python tiene un operador condicional ternario?

-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
Visualización de my_list [0, 1, 2, 3, 4, 5]
Visualización 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]

2
  • ¿Qué significa "Affichage de ..." ? ¿Es francés? Peter Mortensen 22/04/20 a las 14:11
  • @PeterMortensen En francés, significa "Visualización / descripción general de". EntoncesDisplaying / overview of my_result_list ... Nomad 10/06/20 a las 10:44