【问题标题】:Python AND operator on two boolean lists - how?两个布尔列表上的 Python AND 运算符 - 如何?
【发布时间】:2015-11-18 11:00:39
【问题描述】:

我有两个布尔列表,例如,

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)

【问题讨论】:

  • x 是一个列表,y 是一个列表。 x and y 为真当且仅当两个列表都是非空的(空列表是 'false-y',所有非空列表都是 'truth-y'):也就是说,x and y '和每个元素' 或以其他方式关心值。

标签: python list boolean operator-keyword


【解决方案1】:

and 只是根据它们的真值返回第一个或第二个操作数。如果第一个操作数为假,则返回,否则返回另一个操作数。

列表在非空时被认为是true,因此两个列表都被认为是true。它们的内容在这里没有作用

因为两个列表都不为空,x and y 只是简单地返回第二个列表对象;只有x 为空才会被返回:

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

请参阅 Python 文档中的 Truth value testing section

可以测试任何对象的真值,用于ifwhile 条件或作为以下布尔运算的操作数。以下值被认为是错误的:

[...]

  • 任何空序列,例如,''()[]

[...]

所有其他值都被认为是真——因此许多类型的对象总是真。

(强调我的),以及正下方的Boolean operations section

x and y
如果 x 为假,则 x,否则 y

这是一个短路运算符,所以它只计算第二个参数,如果第一个参数是True

您确实需要明确地测试列表中包含 的值。正如您所发现的,您可以通过列表理解来做到这一点。您可以使用 zip() function 重写它以配对值:

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

【讨论】:

  • 感谢出色的解释和特别是。重复我所看到的“如果 x 为假,则 x,否则 y”,但没有完全理解。这是RTFM的一个案例,我应该非常仔细地阅读它!
【解决方案2】:

你可以使用 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)

【讨论】:

    【解决方案3】:

    这是一个简单的解决方案:

    np.logical_and(x,y)
    

    【讨论】:

      【解决方案4】:

      and 不一定是布尔运算符;它返回它的两个参数之一,而不管它们的类型。如果第一个参数是假的(False、数字零或空字符串/容器),则返回该参数。否则,它返回第二个参数。

      在您的情况下,xy 都是非空列表,因此第一个参数始终为真,这意味着 x and y 返回 yy and x 返回 x

      【讨论】:

        【解决方案5】:

        这应该做你想做的:

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

        x and y 返回yy and x 返回x 的原因是因为python 中的布尔运算符返回检查的最后一个值,该值确定表达式的真实性。非空 list 的计算结果为 True,并且由于 and 要求两个操作数都计算 True,因此检查的最后一个操作数是第二个操作数。与 x or y 对比,后者将返回 x,因为它不需要检查 y 来确定表达式的真实性。

        【讨论】:

          【解决方案6】:

          而不是使用

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

          可以只使用 numpy 的可能性来乘以布尔值:

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

          还是我忽略了一个特殊情况?

          【讨论】:

            【解决方案7】:

            要概括 zip 方法,请对任意数量的列表使用 allany

            all 与:

            [all(i) for i in zip(a, b, c)]  # zip all lists
            

            any 用于 OR:

            [any(i) for i in zip(a, b, c)]
            

            【讨论】:

              【解决方案8】:

              你可以使用zip函数

              x=[True,True,False,False]
              y=[True,False,True,False]
              z=[a and b for a,b in zip(x,y)]
              

              【讨论】:

                【解决方案9】:

                除了@Martijn Pieters 已经回答的内容之外,我只想添加以下代码来解释andor 的实际操作。

                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]

                【讨论】:

                  【解决方案10】:

                  感谢@Martijn Pieters 和@Tony 的回答。 我深入研究了我们必须对两个列表进行 AND 的各种选项的时间安排,我想分享我的结果,因为我发现它们很有趣。

                  尽管非常喜欢 Python 的方式 [a 和 b 用于 a,b in zip(x,y) ],但结果确实很慢。 我与数组的整数乘积 (1*(array of bool)) * (1*(array of 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
                  

                  速度几乎同样受数组大小或周期数的影响。
                  我希望我帮助某人编码更快。 :-)

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2016-08-16
                    • 1970-01-01
                    • 2013-06-06
                    • 1970-01-01
                    • 2014-01-30
                    • 2014-01-10
                    • 2014-06-09
                    • 2017-09-28
                    相关资源
                    最近更新 更多