Как применить логический оператор ко всем элементам в списке Python

90

У меня есть список логических значений в Python. Я хочу И (или ИЛИ, или НЕ) их и получить результат. Следующий код работает, но не очень питонический.

def apply_and(alist):
 if len(alist) > 1:
     return alist[0] and apply_and(alist[1:])
 else:
     return alist[0]

Любые предложения о том, как сделать его более питоническим, приветствуются.

Роберт Кристи
источник

Ответы:

176

Логично andдля всех элементов в a_list:

all(a_list)

Логично orдля всех элементов в a_list:

any(a_list)

Если вы чувствуете себя творчески, вы также можете:

import operator
def my_all(a_list):
  return reduce(operator.and_, a_list, True)

def my_any(a_list):
  return reduce(operator.or_, a_list, False)

имейте в виду, что они не оцениваются при коротком замыкании, в то время как встроенные ;-)

еще один забавный способ:

def my_all_v2(a_list):
  return len(filter(None,a_list)) == len(a_list)

def my_any_v2(a_list):
  return len(filter(None,a_list)) > 0

и еще один:

def my_all_v3(a_list):
  for i in a_list:
    if not i:
      return False
  return True

def my_any_v3(a_list):
  for i in a_list:
    if i:
      return True
  return False

и мы могли бы продолжать весь день, но да, питонический способ - использовать allи any:-)

Кстати, в Python нет исключения хвостовой рекурсии, поэтому не пытайтесь напрямую переводить код LISP ;-)

Фортран
источник
8
operator.and_ - это побитовый оператор and, а не логический and.
Ants Aasma
1
к счастью, True и False (как и требовалось оператору) приводятся к 1 и 0 соответственно, поэтому побитовые операторы работают как логические ^ _ ^
fortran
6
Объяснил множество повторяющихся версий, но не предоставил синтаксис для фактического правильного ответа.
jwg
2
не соглашайтесь с чем хотите, это в часто задаваемых вопросах: stackoverflow.com/privileges/vote-down
fortran
2
Обратите внимание, что reduce()это functoolsс Python 3.0
Дункан WP
33

И и ИЛИ легко:

>>> some_list = [True] * 100
# OR
>>> any(some_list)
True
#AND
>>> all(some_list)
True
>>> some_list[0] = False
>>> any(some_list)
True
>>> all(some_list)
False

Отметить также довольно просто:

>>> [not x for x in some_list]
[True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]

Конечно, использование этих результатов может потребовать некоторых интересных приложений теоремы ДеМоргана.

Джейсон Бейкер
источник
4
Если вы хотите обойти вариант not, просто используйте выражения генератора: all(not x for x in some_list)(но это то же самое, что и not any(some_list)(вполне естественное выражение, да?)).
u0b34a0f6ae
16

Reduce может сделать это:

reduce(lambda a,b: a and b, alist, True)

Как уже упоминал Фортран, это самый лаконичный способ сделать это. Но сокращение дает ответы на более общий вопрос: «Как применить логический оператор ко всем элементам в списке Python?»

Франк Крюгер
источник
4
сокращение не уходит, AFAIK. он перемещается в модуль functools с его предыдущей позиции в глобальном пространстве имен
Эли Бендерский
1
@eliben: Зачем говорить о Python 3 в будущем времени? сокращение все еще существует . reduceнаходится functools.reduce в Python 3
u0b34a0f6ae
Если вы удалите , True, этот ответ будет единственным, фактически эквивалентным коду вопроса для небулевых списков.
Thomas Ahle
10

Идиома для таких операций заключается в использовании reduceфункции (глобальной в Python 2.X, в модуле functoolsв Python 3.X) с соответствующим двоичным оператором, взятым из operatorмодуля или явно закодированным. В вашем случае этоoperator.and_

reduce(operator.and_, [True, True, False])
Эли Бендерский
источник
4

Вот еще одно решение:

def my_and(a_list):
    return not (False in a_list)

def my_or(a_list):
    return True in a_list

Операция AND для всех элементов вернет True, если все элементы имеют значение True, следовательно, в списке нет False. Операция ИЛИ аналогична, но она должна возвращать True, если в списке присутствует хотя бы одно значение True.

Xarts
источник
0

Как показывают другие ответы, есть несколько способов выполнить эту задачу. Вот еще одно решение, использующее функции из стандартной библиотеки:

from functools import partial

apply_and = all
apply_or = any
apply_not = partial(map, lambda x: not x)

if __name__ == "__main__":
    ls = [True, True, False, True, False, True]
    print "Original: ", ls
    print "and: ", apply_and(ls)
    print "or: ", apply_or(ls)
    print "not: ", apply_not(ls)
мипади
источник