Python 两个布尔列表上的 AND 运算符 - 怎么样?
Python AND operator on two boolean lists - how?
我有两个布尔列表,例如
x=[True,True,False,False]
y=[True,False,True,False]
我想将这些列表与预期的输出相结合:
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]
使用列表理解 是否有正确的输出。哇!
xy = [x[i] and y[i] for i in range(len(x)]
请注意,我找不到任何参考资料告诉我 AND 运算符可以像我尝试使用 x 和 y 那样工作。但是在 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)
这应该可以满足您的要求:
xy = [a and b for a, b in zip(x, y)]
x and y
returns y
和 y and x
returns x
的原因是因为 python 中的布尔运算符return 确定表达式真实性的最后一个检查值。非空 list
的计算结果为 True
,并且由于 and
需要两个操作数来计算 True
,最后检查的操作数是第二个操作数。与 x or y
对比,后者会 return x
因为它不需要检查 y
来确定表达式的真实性。
您可以使用zip
函数
x=[True,True,False,False]
y=[True,False,True,False]
z=[a and b for a,b in zip(x,y)]
and
只是 returns 第一个或第二个操作数,基于它们的真值。如果第一个操作数被认为是 false,则返回它,否则返回另一个操作数。
当 不为空 时,列表被视为 true,因此两个列表都被视为 true。它们的内容在这里不起作用。
因为两个列表都不为空,x and y
简单地returns第二个列表对象;只有当 x
为空时才会返回:
>>> [True, False] and ['foo', 'bar']
['foo', 'bar']
>>> [] and ['foo', 'bar']
[]
请参阅 Python 文档中的 Truth value testing section:
Any object can be tested for truth value, for use in an if
or while
condition or as operand of the Boolean operations below. The following values are considered false:
[...]
- any empty sequence, for example,
''
, ()
, []
.
[...]
All other values are considered true — so objects of many types are always true.
(强调我的),以及正下方的 Boolean operations section:
x and y
if x is false, then x, else y
This is a short-circuit operator, so it only evaluates the second argument if the first one is True
.
您确实需要明确测试列表中 contained 的值。正如您发现的那样,您可以通过列表理解来做到这一点。您可以使用 zip()
function 重写它以配对值:
[a and b for a, b in zip(x, y)]
and
不一定是布尔运算符;它 returns 它的两个参数之一,无论它们的类型如何。如果第一个参数是 false-ish(False
、数字零或空 string/container),则它 returns 该参数。否则,它 returns 第二个参数。
在你的例子中,x
和 y
都是非空列表,所以第一个参数总是 true-ish,意思是 x and y
returns y
和 y and x
returns x
.
你可以使用 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)
而不是使用
[a and b for a, b in zip(x, y)]
可以利用 numpy 的可能性来乘以布尔值:
(np.array(x)*np.array(y))
>> array([ True, False, False, False], dtype=bool)
还是我忽略了一个特例?
除了@Martijn Pieters 已经回答的内容之外,我只想添加以下代码来解释 and
和 or
操作。
and
returns 遇到的第一个虚假值否则是最后评估的参数。
类似地 or
returns 遇到第一个真值,否则最后一个评估的参数。
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]
感谢@Martijn Pieters 和@Tony 的回答。
我深入研究了我们必须对两个列表进行 AND 操作的各种选项的时间安排,我想分享我的结果,因为我发现它们很有趣。
尽管很喜欢 pythonic 方式 [a and b for a,b in zip(x,y) ],但结果真的很慢。
我与数组的整数乘积 (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
数组大小或循环次数对速度的影响几乎相同。
我希望我帮助某人编码更快。 :-)
这是一个简单的解决方案:
np.logical_and(x,y)
要概括 zip 方法,对任意数量的列表使用 all
和 any
。
all
和:
[all(i) for i in zip(a, b, c)] # zip all lists
和 any
或:
[any(i) for i in zip(a, b, c)]
我有两个布尔列表,例如
x=[True,True,False,False]
y=[True,False,True,False]
我想将这些列表与预期的输出相结合:
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]
使用列表理解 是否有正确的输出。哇!
xy = [x[i] and y[i] for i in range(len(x)]
请注意,我找不到任何参考资料告诉我 AND 运算符可以像我尝试使用 x 和 y 那样工作。但是在 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)
这应该可以满足您的要求:
xy = [a and b for a, b in zip(x, y)]
x and y
returns y
和 y and x
returns x
的原因是因为 python 中的布尔运算符return 确定表达式真实性的最后一个检查值。非空 list
的计算结果为 True
,并且由于 and
需要两个操作数来计算 True
,最后检查的操作数是第二个操作数。与 x or y
对比,后者会 return x
因为它不需要检查 y
来确定表达式的真实性。
您可以使用zip
函数
x=[True,True,False,False]
y=[True,False,True,False]
z=[a and b for a,b in zip(x,y)]
and
只是 returns 第一个或第二个操作数,基于它们的真值。如果第一个操作数被认为是 false,则返回它,否则返回另一个操作数。
当 不为空 时,列表被视为 true,因此两个列表都被视为 true。它们的内容在这里不起作用。
因为两个列表都不为空,x and y
简单地returns第二个列表对象;只有当 x
为空时才会返回:
>>> [True, False] and ['foo', 'bar']
['foo', 'bar']
>>> [] and ['foo', 'bar']
[]
请参阅 Python 文档中的 Truth value testing section:
Any object can be tested for truth value, for use in an
if
orwhile
condition or as operand of the Boolean operations below. The following values are considered false:[...]
- any empty sequence, for example,
''
,()
,[]
.[...]
All other values are considered true — so objects of many types are always true.
(强调我的),以及正下方的 Boolean operations section:
x and y
if x is false, then x, else yThis is a short-circuit operator, so it only evaluates the second argument if the first one is
True
.
您确实需要明确测试列表中 contained 的值。正如您发现的那样,您可以通过列表理解来做到这一点。您可以使用 zip()
function 重写它以配对值:
[a and b for a, b in zip(x, y)]
and
不一定是布尔运算符;它 returns 它的两个参数之一,无论它们的类型如何。如果第一个参数是 false-ish(False
、数字零或空 string/container),则它 returns 该参数。否则,它 returns 第二个参数。
在你的例子中,x
和 y
都是非空列表,所以第一个参数总是 true-ish,意思是 x and y
returns y
和 y and x
returns x
.
你可以使用 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)
而不是使用
[a and b for a, b in zip(x, y)]
可以利用 numpy 的可能性来乘以布尔值:
(np.array(x)*np.array(y))
>> array([ True, False, False, False], dtype=bool)
还是我忽略了一个特例?
除了@Martijn Pieters 已经回答的内容之外,我只想添加以下代码来解释 and
和 or
操作。
and
returns 遇到的第一个虚假值否则是最后评估的参数。
类似地 or
returns 遇到第一个真值,否则最后一个评估的参数。
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]
感谢@Martijn Pieters 和@Tony 的回答。 我深入研究了我们必须对两个列表进行 AND 操作的各种选项的时间安排,我想分享我的结果,因为我发现它们很有趣。
尽管很喜欢 pythonic 方式 [a and b for a,b in zip(x,y) ],但结果真的很慢。 我与数组的整数乘积 (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
数组大小或循环次数对速度的影响几乎相同。
我希望我帮助某人编码更快。 :-)
这是一个简单的解决方案:
np.logical_and(x,y)
要概括 zip 方法,对任意数量的列表使用 all
和 any
。
all
和:
[all(i) for i in zip(a, b, c)] # zip all lists
和 any
或:
[any(i) for i in zip(a, b, c)]