849 Stimmen

Wie testet man mehrere Variablen auf Gleichheit gegenüber einem einzelnen Wert?

Ich versuche, eine Funktion zu erstellen, die mehrere Variablen mit einem Integer vergleicht und einen String aus drei Buchstaben ausgibt. Ich frage mich, ob es eine Möglichkeit gibt, dies in Python zu übersetzen. Also sagen Sie:

x = 0
y = 1
z = 3
mylist = []

if x or y or z == 0:
    mylist.append("c")
if x or y or z == 1:
    mylist.append("d")
if x or y or z == 2:
    mylist.append("e")
if x or y or z == 3: 
    mylist.append("f")

was eine Liste von zurückgeben würde:

["c", "d", "f"]

8 Stimmen

Verwenden Sie 1 im (Tuple)

7 Stimmen

Wenn Sie eine Liste von Aussagen auf irgendeine Weise bewerten möchten, können Sie die Funktionen any/all verwenden. Zum Beispiel: all([1, 2, 3, 4, False]) gibt False zurück all([True, 1, 2, 3]) gibt True zurück any([False, 0, 0, False]) gibt False zurück any([False, 0, True, False]) gibt True zurück

0 Stimmen

Ich habe einen Zusammenfassungsbeitrag basierend auf den Antworten hier gemacht: medium.com/codervlogger/…

1126voto

Martijn Pieters Punkte 953257

Sie verstehen nicht, wie boolesche Ausdrücke funktionieren; sie funktionieren nicht wie ein englischer Satz und vermuten, dass Sie über den gleichen Vergleich für alle Namen hier sprechen. Sie suchen nach:

if x == 1 or y == 1 or z == 1:

x und y werden sonst einzeln ausgewertet (False wenn 0, sonst True).

Sie können das verkürzen, indem Sie einen Entainment-Test gegen ein Tupel verwenden:

if 1 in (x, y, z):

oder noch besser:

if 1 in {x, y, z}:

unter Verwendung einer Menge, um von den konstanten Kosten des Membership-Tests zu profitieren (d. h. in dauert unabhängig vom linken Operanden eine feste Zeit).

Erklärung

Wenn Sie or verwenden, betrachtet Python jede Seite des Operators als getrennte Ausdrücke. Der Ausdruck x or y == 1 wird zuerst als boolescher Test für x behandelt, dann wird, wenn dies False ist, der Ausdruck y == 1 getestet.

Dies liegt an der Operator-Präzedenz. Der Operator or hat eine niedrigere Präzedenz als der Test ==, daher wird letzterer zuerst ausgewertet.

Auch wenn dies nicht der Fall wäre und der Ausdruck x or y or z == 1(x or y or z) == 1 interpretiert würde, würde dies immer noch nicht tun, was Sie erwarten.

x or y or z würde sich auf das erste Argument auflösen, das 'truthy', d. h. nicht False, numerisch 0 oder leer, ist (siehe boolesche Ausdrücke für Details dazu, was Python in einem booleschen Kontext als falsch betrachtet).

Also für die Werte x = 2; y = 1; z = 0 würde x or y or z zu 2 auflösen, weil das der erste wahrheitsähnliche Wert in den Argumenten ist. Dann würde 2 == 1 zu False werden, obwohl y == 1 zu True wird.

Dasselbe würde für das Gegenteil gelten; das Testen mehrerer Werte gegen eine einzelne Variable; x == 1 or 2 or 3 würde aus den gleichen Gründen scheitern. Verwenden Sie x == 1 or x == 2 or x == 3 oder x in {1, 2, 3}.

155 Stimmen

Ich würde nicht so schnell zur set-Version gehen. Tupel sind sehr einfach zu erstellen und zu durchlaufen. Zumindest auf meinem Computer sind Tupel schneller als Sets, solange die Größe des Tupels etwa 4-8 Elemente beträgt. Wenn Sie mehr als das durchsuchen müssen, verwenden Sie ein Set, aber wenn Sie nach einem Element aus 2-4 Möglichkeiten suchen, ist ein Tupel immer noch schneller! Wenn Sie dafür sorgen können, dass der wahrscheinlichste Fall als erstes im Tupel steht, ist der Gewinn noch größer: (mein Test: timeit.timeit('0 in {seq}'.format(seq=tuple(range(9,-1,-1 )))))

71 Stimmen

@dequestarmappartialsetattr: In Python 3.3 und höher wird das Set als Konstante gespeichert, wodurch die Erstellungszeit vollständig umgangen und eliminiert wird. Tupel können günstig erstellt werden, da Python eine Vielzahl von ihnen zwischenspeichert, um Speicherumschichtungen zu vermeiden. Das ist der größte Unterschied zu Sets hier.

18 Stimmen

@dequestarmappartialsetattr: Wenn Sie nur den Mitgliedschaftstest timen, sind für den idealen Szenario Ganzzahlensets und Tupel gleichermaßen schnell, um das erste Element abzugleichen. Danach verlieren Tupel gegenüber Sets.

118voto

dansalmo Punkte 10858

Ihr Problem kann leichter mit einer Wörterbuchstruktur gelöst werden, wie:

x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]

27 Stimmen

Oder sogar d = "cdef", was zu MyList = ["cdef"[k] for k in [x, y, z]] führt

11 Stimmen

Oder map(lambda i: 'cdef'[i], [x, y, z])

2 Stimmen

Abgesehen von der Listenkomprehension, mit der ich noch nicht ganz vertraut bin, hatten die meisten von uns den gleichen Reflex: dieses Dict erstellen !

78voto

ThatGuyRussell Punkte 1351

Wie von Martijn Pieters angegeben, ist das korrekte und schnellste Format:

if 1 in {x, y, z}:

Wenn Sie seinem Rat folgen, würden Sie nun separate if-Anweisungen haben, damit Python jede Anweisung liest, unabhängig davon, ob die vorherigen True oder False waren. Zum Beispiel:

if 0 in {x, y, z}:
    mylist.append("c")
if 1 in {x, y, z}:
    mylist.append("d")
if 2 in {x, y, z}:
    mylist.append("e")
...

Dies funktioniert, aber wenn Sie sich mit dem Verwenden von Wörterbüchern wohl fühlen (sehen Sie, was ich dort gemacht habe), können Sie dies aufräumen, indem Sie ein anfängliches Wörterbuch erstellen, das die Zahlen den Buchstaben zuordnet, die Sie möchten, und dann einfach eine for-Schleife verwenden:

num_to_letters = {0: "c", 1: "d", 2: "e", 3: "f"}
for number in num_to_letters:
    if number in {x, y, z}:
        mylist.append(num_to_letters[number])

1 Stimmen

@VisioN Du meinst for number in num_to_letters? Du brauchst kein .keys(), Dicts durchlaufen standardmäßig die Schlüssel. Bezüglich der Verwendung eines Strings meinst du sowas, richtig? for i, c in enumerate('cdef'): if i in {x, y, z}: mylist.append(c) Einverstanden, das wäre einfacher. Oder noch besser, s = 'cdef'; mylist = [s[i] for i in [x, y, z]]

0 Stimmen

@wjandrea Ja, du hast recht, es ist mein Fehler! Ich habe völlig vergessen, wie das Standardverhalten ist. Leider kann ich meinen Kommentar nicht bearbeiten, also habe ich ihn gelöscht, da du den besseren Ansatz in deinem Kommentar hervorgehoben hast.

56voto

akaRem Punkte 6956

Der direkte Weg, x oder y oder z == 0 zu schreiben, ist

if any(map((lambda value: value == 0), (x,y,z))):
    pass # write your logic.

Aber ich denke nicht, dass es dir gefällt. :) Und dieser Weg ist hässlich.

Der andere Weg (besser) ist:

0 in (x, y, z)

Übrigens könnten viele if-Anweisungen so geschrieben werden

my_cases = {
    0: Mylist.append("c"),
    1: Mylist.append("d")
    # ..
}

for key in my_cases:
    if key in (x,y,z):
        my_cases[key]()
        break

9 Stimmen

In Ihrem Beispiel des dict bekommen Sie statt einem Schlüssel Fehler, weil der Rückgabewert von .append None ist und das Aufrufen von None einen AttributeError gibt. Im Allgemeinen stimme ich jedoch mit dieser Methode überein.

4 Stimmen

Der Wert des Dictionaries anstelle eines Schlüssels ist falsch, Sie erhalten Mylist=['c', 'd'], wenn das Dictionary initialisiert wird, auch wenn Sie den "for..Schleifen"-Teil auskommentiert haben.

2 Stimmen

In deinem ersten Beispiel wäre filter besser als map, da es nur Instanzen zurückgibt, bei denen lambda zu true ausgewertet wird

35voto

rassa45 Punkte 3400

Wenn du SEHR faul bist, kannst du die Werte in ein Array legen. Zum Beispiel

list = []
list.append(x)
list.append(y)
list.append(z)
nums = [füge hier Zahlen ein]
letters = [füge entsprechende Buchstaben hier ein]
for index in range(len(nums)):
    for obj in list:
        if obj == num[index]:
            MyList.append(letters[index])
            break

Du kannst auch die Zahlen und Buchstaben in einem Wörterbuch ablegen und es machen, aber das ist wahrscheinlich VIEL komplizierter als nur wenn Anweisungen. Das bekommst du, wenn du versuchst extra faul zu sein :)

Noch etwas, dein

if x or y or z == 0:

wird kompilieren, aber nicht so, wie du es möchtest. Wenn du einfach eine Variable in einer If-Anweisung setzt (Beispiel)

if b

wird das Programm überprüfen, ob die Variable nicht null ist. Eine andere Möglichkeit, die obige Anweisung zu schreiben (was mehr Sinn macht) ist

if bool(b)

Bool ist eine eingebaute Funktion in Python, die im Grunde genommen den Befehl ausführt, eine boolsche Aussage zu überprüfen (Wenn du nicht weißt, was das ist, ist es das, was du gerade in deiner if-Anweisung machen möchtest :))

Ein anderer fauler Weg, den ich gefunden habe, ist :

if any([x==0, y==0, z==0])

9 Stimmen

- Hier gibt es viele schlechte Praktiken. list ist eine Python-Builtin; verwenden Sie stattdessen einen anderen Namen, z. B. xyz. Warum konstruieren Sie die Liste in vier Schritten, wenn Sie es in einem einzigen machen können, d.h. xyz = [x, y, z]? Verwenden Sie keine parallelen Listen, verwenden Sie stattdessen ein Dictionary. Alles in allem ist diese Lösung viel verworrener als die von ThatGuyRussell. Auch für den letzten Teil, warum nicht eine List Comprehension machen, d.h. any(v == 0 for v in (x, y, z))? Auch Arrays sind in Python etwas anderes.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X