Como aplicar um operador lógico a todos os elementos em uma lista python

93

Eu tenho uma lista de booleanos em python. Eu quero AND (ou OR ou NOT) e obter o resultado. O código a seguir funciona, mas não é muito pitônico.

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

Quaisquer sugestões sobre como torná-lo mais pythônico serão apreciadas.

Robert Christie
fonte

Respostas:

181

Lógico andem todos os elementos em a_list:

all(a_list)

Lógico orem todos os elementos em a_list:

any(a_list)

Se você se sentir criativo, também pode fazer:

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)

tenha em mente que aqueles não são avaliados em curto-circuito, enquanto os integrados são ;-)

outra maneira engraçada:

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

e ainda outro:

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

e poderíamos continuar o dia todo, mas sim, a forma pythônica é usar alle any:-)

A propósito, Python não tem eliminação de recursão de cauda, ​​então não tente traduzir o código LISP diretamente ;-)

Fortran
fonte
8
operator.and_ é o operador bit a bit and &, não o lógico e.
Formigas Aasma
1
felizmente True e False (como o op queria) são convertidos em 1 e 0 respectivamente, de modo que os operadores bit a bit funcionam como o ^ _ ^
fortran
6
Explicou várias versões redundantes, mas não forneceu a sintaxe para a resposta correta real.
jwg de
2
discorde do que quiser, está no faq: stackoverflow.com/privileges/vote-down
fortran
2
Observe que reduce()está disponível functoolsdesde Python 3.0
Duncan WP
33

ANDing e ORing é fácil:

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

NOTAR também é bastante fácil:

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

Claro, como você usaria esses resultados pode exigir algumas aplicações interessantes do teorema de DeMorgan.

Jason Baker
fonte
4
Se você quiser curto-circuitar a variante não, simplesmente use expressões geradoras: all(not x for x in some_list)(mas isso é o mesmo que not any(some_list)(uma expressão bastante natural, hein?)).
u0b34a0f6ae
16

Reduzir pode fazer isso:

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

Quanto ao fortran mencionado, tudo é a maneira mais sucinta de fazer isso. Mas a redução responde à questão mais geral "Como aplicar um operador lógico a todos os elementos em uma lista python?"

Frank Krueger
fonte
4
reduzir não está indo embora, AFAIK. está sendo movido para o módulo functools, de sua posição anterior no namespace global
Eli Bendersky
1
@eliben: Por que falar sobre Python 3 no tempo futuro? reduzir ainda está lá . reduceestá functools.reduce em Python 3
u0b34a0f6ae
Se você remover o , True, esta resposta será a única realmente equivalente ao código da pergunta, para listas não booleanas.
Thomas Ahle de
10

O idioma para tais operações é usar a reducefunção (global em Python 2.X, em módulo functoolsem Python 3.X) com um operador binário apropriado retirado do operatormódulo ou codificado explicitamente. No seu caso, éoperator.and_

reduce(operator.and_, [True, True, False])
Eli Bendersky
fonte
4

Aqui está outra solução:

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

def my_or(a_list):
    return True in a_list

Fazer AND de todos os elementos retornará True se todos os elementos forem True, portanto, nenhum False em uma lista. ORing é semelhante, mas deve retornar True se pelo menos um valor True estiver presente em uma lista.

Xarts
fonte
0

Como mostram as outras respostas, existem várias maneiras de realizar essa tarefa. Aqui está outra solução que usa funções da biblioteca padrão:

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