Подтвердить что ты не робот

Оператор Python AND в двух логических списках - как?

У меня есть два булевых списка, например,

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

Ответ 1

and просто возвращает либо первый, либо второй операнд, основываясь на их значении истинности. Если первый операнд считается ложным, он возвращается, в противном случае возвращается другой операнд.

Списки считаются истинными, когда они не пусты, поэтому оба списка считаются истинными. Их содержание здесь не играет роли.

Поскольку оба списка не пусты, x and y просто возвращает второй объект списка; только если x пуст, он будет возвращен:

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

См. раздел Раздел тестирования значения правды в документации Python:

Любой объект может быть проверен на значение истины, для использования в состоянии if или while или в качестве операнда булевых операций ниже. Следующие значения считаются ложными:

[...]

  • любая пустая последовательность, например '', (), [].

[...]

Все остальные значения считаются истинными, поэтому объекты многих типов всегда верны.

(выделение мое) и раздел логических операций, расположенный ниже:

x and y
если x ложно, то x, else y

Это оператор короткого замыкания, поэтому он вычисляет только второй аргумент, если первый True.

Вам действительно нужно проверить значения, содержащиеся в списках, явно. Вы можете сделать это со списком, как вы обнаружили. Вы можете переписать его с помощью функции zip(), чтобы соединить значения:

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

Ответ 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

and не обязательно является булевым оператором; он возвращает один из двух своих аргументов, независимо от их типа. Если первым аргументом является false-ish (False, числовой ноль или пустая строка/контейнер), он возвращает этот аргумент. В противном случае он возвращает второй аргумент.

В вашем случае оба x и y являются непустыми списками, поэтому первый аргумент всегда имеет значение true-ish, то есть x and y возвращает y и y and x возвращает x.

Ответ 4

Это должно делать то, что вы хотите:

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

Причина x and y возвращает y и y and x возвращает x потому, что логические операторы в python возвращают последнее проверенное значение, которое определяет истинность выражения. Непустой list оценивается до True, и поскольку and требует, чтобы оба операнда оценивали True, последний проверенный операнд является вторым операндом. Контраст с x or y, который вернет x, потому что не нужно проверять y, чтобы определить истинность выражения.

Ответ 5

Вместо использования

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

можно было просто использовать возможность numpy умножить значения bool:

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

Или я не вижу специального случая?

Ответ 6

Вы можете использовать функцию zip

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

Ответ 7

В дополнение к тому, что @Martijn Питерс ответил, я бы просто добавить следующий код, чтобы объяснить 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]

Ответ 8

Спасибо за ответ @Martijn Pieters и @Tony. Я копаю во времени различные варианты, которые мы должны сделать, И для двух списков, и я хотел бы поделиться своими результатами, потому что я нашел их интересными.

Несмотря на большой интерес к питону [a и b для a, b в 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

Скорость почти одинаково зависит от размера массива или количества циклов.
Я надеюсь, что помог кому-то код, чтобы быть быстрее. :-)