web-dev-qa-db-ja.com

Python 2つのブールリストのAND演算子-どうやって?

私は2つのブールリストを持っています、例えば、

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

これらのリストを、期待される出力とともにANDしたいです。

xy=[True,False,False,False]

x and yは機能すると思っていましたが、実際にはそうではないことがわかりました。実際、(x and y) != (y and x)

x and yの出力:[True,False,True,False]

y and xの出力:[True,True,False,False]

リスト内包表記doesを使用すると、正しい出力が得られます。ふう!

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

念のため、xとyで試したときにAND演算子が機能することを教えてくれる参照が見つかりませんでした。しかし、Pythonで簡単に試すことができます。誰かがx and yで何が起こっているのか説明してもらえますか?

そして、ここに簡単なテストプログラムがあります:

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)
33
Glenn N

andは、真理値に基づいて、第1オペランドまたは第2オペランドのいずれかを単に返します。最初のオペランドが偽と見なされる場合はそれが返され、そうでない場合は他のオペランドが返されます。

リストはtrueと見なされますnot emptyであるため、両方のリストはtrueと見なされます。それらの内容はここでは役割を果たしません

両方のリストが空ではないため、_x and y_は単に2番目のリストオブジェクトを返します。 xが空の場合のみ、代わりに返されます。

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

Pythonドキュメント: Truth value testingセクション を参照してください:

ifまたはwhile条件で使用するため、または以下のブール演算のオペランドとして、任意のオブジェクトを真理値でテストできます。次の値は偽と見なされます。

[...]

  • 空のシーケンス。たとえば、_''_、_()_、_[]_。

[...]

他のすべての値はtrueとみなされます—そのため、多くのタイプのオブジェクトは常にtrueです。

(強調鉱山)、および ブール演算セクション そのすぐ下:

_x and y_
ifxがfalseの場合、x、elsey

これは短絡演算子であるため、最初の引数がTrueである場合にのみ2番目の引数を評価します。

実際、リスト内の値containedを明示的にテストする必要があります。あなたが発見したように、あなたはリストの理解でそうすることができます。 Zip() function で書き換えて、値をペアにすることができます。

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

Numpyを使用できます:

>>> 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では、次のような配列の数値および論理演算が可能です。

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

ビット単位で実行でき、&演算子。

リスト内包表記の代わりに、次のようにnumpyを使用してブール配列を直接生成できます。

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

andは必ずしもブール演算子ではありません。型に関係なく、2つの引数のいずれかを返します。最初の引数が偽っぽい場合(False、数値のゼロ、または空の文字列/コンテナ)、その引数を返します。それ以外の場合は、2番目の引数を返します。

あなたの場合、xyの両方が空ではないリストなので、最初の引数は常に真っぽです。つまり、_x and y_はyと_y and x_はxを返します。

4
chepner

これはあなたが望むことをするはずです:

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

x and yyを返し、y and xxを返す理由は、python空でないlistTrueに評価され、andTrueを評価するために両方のオペランドを必要とするため、最後にチェックされるオペランドは2番目のオペランドx or yとは対照的で、xを確認して式の真偽を判断する必要がないため、yを返します。

2
Cyphase

代わりに

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

numpyの可能性を使用してブール値を乗算できます。

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

または、特別なケースを見落とすことはありますか?

1
Philipp

@Martijn Pietersと@Tonyの回答に感謝します。 2つのリストのANDを作成する必要があるさまざまなオプションのタイミングを調べます。結果が面白いとわかったので、結果を共有したいと思います。

Pythonの方法[Zip(x、y)のa、bのaとb]が非常に好きであるにもかかわらず、本当に遅いことがわかりました。配列の整数積(1 *(boolの配列))*(1 *(boolの配列))と比較すると、10倍以上高速であることがわかりました

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)))

結果は

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

速度は、アレイのサイズまたはサイクル数によってほぼ等しく影響を受けます。
コードの高速化を支援したいと思います。 :-)

0
Marco Triches

Zip関数を使用できます

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

@Martijn Pietersの回答に加えて、次のコードを追加して、andおよびor操作の動作を説明します。

andは、検出された最初の偽の値、または最後に評価された引数を返します。

同様に、orは、最後に評価された引数に遭遇した最初の真理値を返します。

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

値は

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

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

0