if / else in einem Listenverständnis

Antworten:

1460

Das kannst du total machen. Es ist nur ein Bestellproblem:

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

Allgemein,

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

Und für Listenverständnisse ifnur mit Bedingungen,

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

Beachten Sie, dass dies tatsächlich nutzt eine andere Sprachkonstrukt, ein Bedingungsausdruck , der selbst nicht Bestandteil der ist Verständnis Syntax , während der ifnach der for…inTeil der Liste Comprehensions und dazu verwendet, ist Filterelemente von der Quelle iterable.


Bedingte Ausdrücke können in allen Situationen verwendet werden, in denen Sie basierend auf einer bestimmten Bedingung zwischen zwei Ausdruckswerten wählen möchten. Dies entspricht dem ternären Operator ?:, der in anderen Sprachen vorhanden ist . Zum Beispiel:

value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')
Sack
quelle
141
Beachten Sie, dass das if / else hier jetzt die Syntax "ternärer Operator" und nicht die Syntax des Listenverständnisses ist.
Adam Vandenberg
8
Deshalb ziehe ich es vor, den ternären Operator in Klammern zu setzen. Dadurch wird klarer, dass es sich nur um einen normalen Ausdruck handelt, nicht um ein Verständnis.
Jochen Ritzel
17
Der Trick lautet also "Bei der Listenkomprimierung schreibe ich, wenn vorher, dann muss ich auch noch einen anderen Teil hinzufügen". denn wenn meine l = [ 2, 3, 4, 5]dann [x if x % 2 == 0 for x in l]gib mir fehler wohingegen [x if x % 2 == 0 else 200 for x in l]funktioniert. Ja, ich weiß, um es zu filtern, sollte ich schreiben [ x for x in l if x % 2 == 0]. Entschuldigung für die Mühe. Danke für deine Antwort.
Grijesh Chauhan
5
In den Python-Dokumenten wird der ternäre Operator erwähnt . Beachten Sie, dass das else erforderlich ist oder nicht funktioniert.
naught101
4
@Drewdin Listenverständnisse unterstützen das Brechen während der Iteration nicht. Sie müssen dann eine normale Schleife verwenden.
Poke
44

Einweg:

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

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

Obwohl Sie dann haben:

row = map(change, row)

Oder Sie können ein Lambda Inline verwenden.

Adam Vandenberg
quelle
13
Dies ist auch eine gute (möglicherweise einzige) Technik, wenn Sie mögliche Ausnahmen vom ifAusdruck oder Code in seinem oder dem elses-Anweisungsblock behandeln müssen. Die akzeptierte Antwort ist für einfache Fälle besser.
Martineau
37

Hier ist ein weiteres anschauliches Beispiel:

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

Es nutzt die Tatsache aus, dass für und für alle anderen von der Funktion generierten Werte if iausgewertet wird . Daher wird das Listenverständnis wie folgt bewertet:False0Truerange()

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

Das spezifische Problem wurde bereits in früheren Antworten gelöst, daher werde ich auf die allgemeine Idee eingehen, Bedingungen innerhalb des Listenverständnisses zu verwenden.

Hier ist ein Beispiel, das zeigt, wie Bedingungen innerhalb eines Listenverständnisses geschrieben werden können:

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

Beachten Sie, dass im ersten Listenverständnis für X_non_strdie Reihenfolge lautet:

Ausdruck für Element in iterierbarer if- Bedingung

und im letzten Listenverständnis für X_str_changedlautet die Reihenfolge:

Ausdruck1, wenn Bedingung sonst Ausdruck2 für Element in iterable

Es fällt mir immer schwer, mich daran zu erinnern, dass expresseion1 vor if stehen muss und expression2 nach else sein muss . Mein Kopf möchte, dass beide entweder vorher oder nachher sind.

Ich denke, es ist so gestaltet, weil es der normalen Sprache ähnelt, zB "Ich möchte drinnen bleiben, wenn es regnet, sonst möchte ich nach draußen gehen".

Im Klartext können die beiden oben genannten Arten von Listenverständnissen wie folgt angegeben werden:

Mit nur if:

extract_apple für apple in box_of_apples wenn apple_is_ripe

und mit if/else

mark_apple wenn apple_is_ripe sonst leave_it_unmarked für Apfel in box_of_apples

Tim Skov Jacobsen
quelle
7

Die anderen Lösungen eignen sich hervorragend für ein Single if/ elseKonstrukt. Ternäre Aussagen innerhalb des Listenverständnisses sind jedoch wohl schwer zu lesen.

Die Verwendung einer Funktion verbessert die Lesbarkeit, aber eine solche Lösung ist in einem Workflow, in dem das Mapping eine Eingabe ist, schwierig zu erweitern oder anzupassen. Ein Wörterbuch kann diese Bedenken lindern:

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
quelle
1

Es hat damit zu tun, wie das Listenverständnis durchgeführt wird.

Beachten Sie Folgendes:

[ expression for item in list if conditional ]

Ist äquivalent zu:

for item in list:
    if conditional:
        expression

Wo das expressionin einem etwas anderen Format ist (denken Sie daran, das Thema und die Verbreihenfolge in einem Satz zu wechseln).

Daher macht Ihr Code [x+1 for x in l if x >= 45]Folgendes:

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

Dieser Code [x+1 if x >= 45 else x+5 for x in l]führt dies jedoch aus (nach dem Neuanordnen des expression):

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

Es besteht keine Notwendigkeit für ternäre wenn / dann / sonst. Meiner Meinung nach erfordert Ihre Frage diese Antwort:

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

Erstellen Sie eine Liste aus Elementen in einer iterierbaren

Es scheint am besten, zuerst alle möglichen Formen zu verallgemeinern, anstatt spezifische Antworten auf Fragen zu geben. Andernfalls weiß der Leser nicht, wie die Antwort ermittelt wurde. Hier sind einige verallgemeinerte Formulare, die ich mir ausgedacht habe, bevor ich Kopfschmerzen bekam, als ich versuchte zu entscheiden, ob im letzten Formular eine letzte else-Klausel verwendet werden könnte.

[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]

Der Wert von itemmuss in keiner der Bedingungsklauseln verwendet werden. A conditional3kann als Schalter verwendet werden, um der Ausgabeliste einen Wert hinzuzufügen oder nicht.

So erstellen Sie beispielsweise eine neue Liste, in der leere Zeichenfolgen oder Leerzeichen aus der ursprünglichen Liste der Zeichenfolgen entfernt werden:

newlist = [s for s in firstlist if s.strip()]
Hewey Dewey
quelle
1
Der zweite gibt einen Fehler aus, als Tim in seinem Kommentar antwortete , siehe auch die bedingten Anweisungen in den Python-Dokumenten. Welche sind für mich ziemlich unlesbar. Zusammenfassung: Nur this if condition else thatoder ein normaler Ausdruck ist zulässig. Nicht value = this if condition(was mit erreicht werden kann value = this if condition else None)
Anderium
0

Sie können bedingte Logik in einem Verständnis kombinieren:

 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
quelle
-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]

Also für dich: row = [('', unicode(x.strip()))[x is not None] for x in row]

Trop Freshloïc
quelle
Was bedeutet "Affichage de ..." ? Ist es französisch?
Peter Mortensen