it-swarm.com.de

Python AND-Operator auf zwei booleschen Listen - wie

Ich habe zwei boolesche Listen, z.

x=[True,True,False,False]
y=[True,False,True,False]

Ich möchte UND diese Listen zusammen mit der erwarteten Ausgabe UND

xy=[True,False,False,False]

Ich dachte, dass der Ausdruck x and y funktionieren würde, kam aber zu der Erkenntnis, dass dies nicht der Fall ist: (x and y) != (y and x)

Ausgabe von x and y: [True,False,True,False]

Ausgabe von y and x: [True,True,False,False]

Listenverständnis verwenden hat korrekte Ausgabe. Wütend!

xy = [x[i] and y[i] for i in range(len(x)]

Wohlgemerkt, ich konnte keine Referenz finden, die besagte, dass der AND-Operator so funktionieren würde, wie ich es mit x und y versuchte. Aber es ist leicht, Dinge in Python auszuprobieren ... Kann mir jemand erklären, was mit x and y passiert?

Und hier ist ein einfaches Testprogramm:

import random
random.seed()
n = 10
x = [random.random() > 0.5 for i in range(n)]
y = [random.random() > 0.5 for i in range(n)]
# Next two methods look sensible, but do not work
a = x and y
z = y and x
# Next: apparently only the list comprehension method is correct
xy = [x[i] and y[i] for i in range(n)]
print 'x        : %s'%str(x)
print 'y        : %s'%str(y)
print 'x and y  : %s'%str(a)
print 'y and x  : %s'%str(z)
print '[x and y]: %s'%str(xy)
24
Glenn N

and gibt einfach entweder den ersten oder den zweiten Operanden zurück, basierend auf ihrem Wahrheitswert. Wenn der erste Operand als falsch betrachtet wird, wird er zurückgegeben, andernfalls wird der andere Operand zurückgegeben.

Listen werden als wahr betrachtet, wenn nicht leer, daher werden beide Listen als wahr betrachtet. Ihr Inhalt spielt hier keine Rolle.

Da beide Listen nicht leer sind, gibt x and y Einfach das zweite Listenobjekt zurück. Nur wenn x leer wäre, würde es stattdessen zurückgegeben:

>>> [True, False] and ['foo', 'bar']
['foo', 'bar']
>>> [] and ['foo', 'bar']
[]

Siehe den Abschnitt Truth value testing in der Dokumentation Python:

Jedes Objekt kann auf Wahrheitswert getestet werden, zur Verwendung in einer if oder while Bedingung oder als Operand der folgenden Booleschen Operationen. Die folgenden Werte gelten als falsch:

[...]

  • eine leere Sequenz, z. B. '', (), [].

[...]

Alle anderen Werte gelten als wahr - daher sind Objekte vieler Typen immer wahr.

(Hervorhebung von mir) und der Abschnitt Boolesche Operationen direkt darunter:

x and y
wenn x falsch ist, dann x, sonst y

Dies ist ein Kurzschlussoperator, daher wird das zweite Argument nur ausgewertet, wenn das erste True ist.

Sie müssen in der Tat die Werte enthalten in den Listen explizit testen. Sie können dies mit einem Listenverständnis tun, wie Sie festgestellt haben. Sie können es mit der Funktion Zip() umschreiben, um die Werte zu koppeln:

[a and b for a, b in Zip(x, y)]
40
Martijn Pieters

Sie könnten numpy verwenden:

>>> import numpy as np
>>> x=np.array([True,True,False,False])
>>> y=np.array([True,False,True,False])
>>> x & y
array([ True, False, False, False], dtype=bool)

Numpy ermöglicht numerische und logische Operationen an Arrays wie:

>>> z=np.array([1,2,3,4])
>>> z+1
array([2, 3, 4, 5])

Sie können bitweise und mit dem Operator & arbeiten.

Anstelle eines Listenverständnisses können Sie mit numpy das boolesche Array direkt wie folgt generieren:

>>> np.random.random(10)>.5
array([ True,  True,  True, False, False,  True,  True, False, False, False], dtype=bool)
6
dawg

and ist nicht notwendigerweise ein boolescher Operator. es gibt eines seiner beiden Argumente zurück, unabhängig von ihrem Typ. Wenn das erste Argument false-ish ist (False, numerische Null oder leere Zeichenfolge/Container), wird dieses Argument zurückgegeben. Andernfalls wird das zweite Argument zurückgegeben.

In Ihrem Fall sind sowohl x als auch y nicht leere Listen, daher ist das erste Argument immer true-ish, dh x and y gibt y zurück und y and x gibt x zurück.

4
chepner

Dies sollte tun, was Sie wollen:

xy = [a and b for a, b in Zip(x, y)]

x and y gibt y zurück und y and x gibt x zurück, weil boolesche Operatoren in Python den letzten überprüften Wert zurückgeben, der die Richtigkeit des Ausdrucks bestimmt. Nicht leere lists werden als True ausgewertet, und da and beide Operanden zur Auswertung von True benötigt, ist der letzte überprüfte Operand der zweite Operand. Im Gegensatz zu x or y würde x zurückgegeben werden, da y nicht überprüft werden muss, um die Richtigkeit des Ausdrucks zu ermitteln.

2
Cyphase

Anstatt zu verwenden

[a and b for a, b in Zip(x, y)]

man könnte einfach die Möglichkeit von numpy nutzen, um bool-Werte zu multiplizieren:

(np.array(x)*np.array(y))
>> array([ True, False, False, False], dtype=bool)

Oder übersehe ich einen Sonderfall?

1
Philipp

Vielen Dank für die Antwort @Martijn Pieters und @Tony . Ich schaue mir das Timing der verschiedenen Optionen an, die wir haben müssen, um das UND von zwei Listen zu erstellen, und ich möchte meine Ergebnisse teilen, weil ich sie interessant fand.

Obwohl ich den pythonischen Weg [a und b für a, b in Zip (x, y)] sehr mag, erweist sich das als sehr langsam .. Ich vergleiche es mit einem ganzzahligen Produkt von Arrays (1 * (Array von Bool)) (1 * (Array von Bool)) und es stellt sich heraus, dass es mehr als 10x schneller ist

import time
import numpy as np
array_to_filter = np.linspace(1,1000000,1000000)                # 1 million of integers :-)
value_limit = 100
cycles = 100

# METHOD #1:  [a and b for a,b in Zip(x,y) ]
t0=time.clock()
for jj in range(cycles):
    x = array_to_filter<np.max(array_to_filter)-value_limit   # filter the values > MAX-value_limit
    y = array_to_filter>value_limit                          # filter the values < value_limit
    z= [a and b for a,b in Zip(x,y) ]                       # AND
    filtered = array_to_filter[z]
print('METHOD #1 = %.2f s' % ( (time.clock()-t0)))



# METHOD 1*(array of bool) AND  1*(array of bool)
t0=time.clock()
for jj in range(cycles):
    x = 1*(array_to_filter<np.max(array_to_filter)-value_limit)   # filter the values > MAX-value_limit
    y = 1*(array_to_filter>value_limit)                          # filter the values < value_limit
    z = x*y                                                     # AND
    z = z.astype(bool)                                          # convert back to array of bool
    filtered = array_to_filter[z]
print('METHOD #2 = %.2f s' % ( (time.clock()-t0)))

Die Ergebnisse sind

METHOD #1 = 15.36 s
METHOD #2 = 1.85 s

Die Geschwindigkeit wird fast gleichermaßen von der Größe des Arrays oder von der Anzahl der Zyklen beeinflusst.
Ich hoffe, ich habe jemandem Code geholfen, schneller zu sein. :-)

0
Marco Triches

Sie können die Funktion Zip verwenden

x=[True,True,False,False]
y=[True,False,True,False]
z=[a and b for a,b in Zip(x,y)]
0
Uri Goren

Zusätzlich zu dem, was @Martijn Pieters geantwortet hat, würde ich einfach den folgenden Code hinzufügen, um and- und or-Vorgänge in Aktion zu erklären.

and gibt den ersten gefundenen falschen Wert zurück, ansonsten das zuletzt bewertete Argument. 

In ähnlicher Weise gibt or den ersten angetroffenen Wahrheitswert zurück, ansonsten das zuletzt bewertete Argument. 

nl1 = [3,3,3,3,0,0,0,0]
nl2 = [2,2,0,0,2,2,0,0]
nl3 = [1,0,1,0,1,0,1,0]
and_list = [a and b and c for a,b,c in Zip(nl1,nl2,nl3)]
or_list = [a or b or c for a,b,c in Zip(nl1,nl2,nl3)]

Werte sind

and_list = [1, 0, 0, 0, 0, 0, 0, 0]

or_list = [3, 3, 3, 3, 2, 2, 1, 0]

0
Tony