Retornando booleano se o conjunto estiver vazio

99

Estou lutando para encontrar uma maneira mais limpa de retornar um valor booleano se meu conjunto estiver vazio no final da minha função

Eu considero a interseção de dois conjuntos e desejo retornar Trueou com Falsebase no fato de o conjunto resultante estar vazio.

def myfunc(a,b):
    c = a.intersection(b)
    #...return boolean here

Meu pensamento inicial foi fazer

return c is not None

No entanto, no meu intérprete, posso ver facilmente que a declaração retornará verdadeira se c = set([])

>>> c = set([])
>>> c is not None
True

Também tentei todos os seguintes:

>>> c == None
False
>>> c == False
False
>>> c is None
False

Agora eu li a partir da documentação que eu só posso usar and, ore notcom conjunto vazio para deduzir um valor booleano. Até agora, a única coisa que posso pensar é retornar, não c

>>> not not c
False
>>> not c
True

Tenho a sensação de que existe uma maneira muito mais pythônica de fazer isso, pois estou lutando para encontrá-la. Não quero retornar o conjunto real para uma instrução if porque não preciso dos valores, só quero saber se eles se cruzam.

CB
fonte
4
conjunto vazio é considerado booleano equivalente falso se você lançá-lo da seguinte forma:bool(set([]))
woozyking
3
a propósito, questão seriamente bem elaborada, o que é notável.
Jonas Schäfer
@JonasWielicki Obrigado! Agradeço a resposta - sabia que era algo nesse sentido.
CB
Essa questão vai fazer 5 anos e ninguém sugeriu usar isdisjoint. Estou completamente chocado.
Adirio

Respostas:

71
def myfunc(a,b):
    c = a.intersection(b)
    return bool(c)

bool()fará algo semelhante not not, mas mais ideomático e claro.

Jonas Schäfer
fonte
9
Eu me oponho, escrever bool(...)quando você está perguntando is_emptyé obscuro. Eu não expresso a intenção.
tamas.kenez
2
@ tamas.kenez Você tem que admitir, porém, que é mais claro do que not not;). (FTR: Eu já votei positivamente na resposta de @gefeis, mas não tenho influência sobre o que o OP aceitou ...)
Jonas Schäfer
113

não tão pítônico quanto as outras respostas, mas matemática:

return len(c) == 0

Como alguns comentários questionaram sobre o impacto que len(set)poderia ter na complexidade. É O (1) conforme mostrado no código-fonte, visto que depende de uma variável que rastreia o uso do conjunto.

static Py_ssize_t
set_len(PyObject *so)
{
    return ((PySetObject *)so)->used;
}
gefei
fonte
10
Eu acho que isso é realmente melhor. Isso torna mais claro qual é sua intenção.
arshajii de
4
Temo que isso terá que ser computado len(c)mesmo se cfor muito grande, o que é desnecessário para verificar se há vazio.
Michele De Pascalis de
1
@Glaedr Eu acredito que cpython len para estruturas de dados comumente usadas (ou seja, lista, conjunto) é O (1) (ou seja, eles armazenam uma variável na estrutura de dados que representa o comprimento)
CB
2
^ +1 @CB eu fiz alguns testes em len (c) e definitivamente é alguma variável que representa len porque houve uma diferença insignificante de tempo de execução quando o tamanho do conjunto mudou drasticamente em ordens de magnitude.
dster77
1
@ dster77 criei o perfil do meu código com ambas as versões e ele foi significativamente mais rápido quando comparado com set()(python 3.5.2 no Windows)
mathiasfk
26

Se você quiser return Truepara um conjunto vazio, então acho que seria mais claro fazer:

return c == set()

ou seja, " cé igual a um vazio set".

(Ou, ao contrário, return c != set()).

Em minha opinião, isso é mais explícito (embora menos idiomático) do que confiar na interpretação do Python de um conjunto vazio como Falseem um contexto booleano.

Jonrsharpe
fonte
2
Na verdade, confiar na interpretação do Python é uma prática muito aceitável. Contanto que suas limitações sejam mantidas em mente.
vulcão
17

Se cé um conjunto, então você pode verificar se ele está vazio, fazendo: return not c.

Se cestiver vazio, então not cestará True.

Caso contrário, se ccontiver algum elemento not cserá False.

Simeon Visser
fonte
7

Quando voce diz:

c is not None

Na verdade, você está verificando se c e None fazem referência ao mesmo objeto. Isso é o que o operador "é" faz. Em python, Nenhum é um valor nulo especial convencionalmente, o que significa que você não tem um valor disponível. Sorta como null em c ou java. Uma vez que o python atribui internamente apenas um valor None usando o operador "is" para verificar se algo é None (pense nulo) funciona, e se tornou o estilo popular. No entanto, isso não tem a ver com o valor verdade do conjunto c, é verificar se c realmente é um conjunto e não um valor nulo.

Se você quiser verificar se um conjunto está vazio em uma instrução condicional, ele é convertido como um booleano no contexto para que você possa apenas dizer:

c = set()
if c:
   print "it has stuff in it"
else:
   print "it is empty"

Mas se quiser que seja convertido em booleano para ser armazenado, você pode simplesmente dizer:

c = set()
c_has_stuff_in_it = bool(c)
Andrew Allaire
fonte
1
"""
This function check if set is empty or not.
>>> c = set([])
>>> set_is_empty(c)
True

:param some_set: set to check if he empty or not.
:return True if empty, False otherwise.
"""
def set_is_empty(some_set):
    return some_set == set()
shtut shtuzim
fonte
0

Não tão limpo quanto o bool (c), mas era uma desculpa para usar o ternário.

def myfunc(a,b):
    return True if a.intersection(b) else False

Também usando um pouco da mesma lógica, não há necessidade de atribuir a c, a menos que você o esteja usando para outra coisa.

def myfunc(a,b):
    return bool(a.intersection(b))

Por fim, suponho que você deseja um valor True / False porque irá realizar algum tipo de teste booleano com ele. Eu recomendaria pular a sobrecarga de uma chamada de função e definição, simplesmente testando onde for necessário.

Ao invés de:

if (myfunc(a,b)):
    # Do something

Talvez isto:

if a.intersection(b):
    # Do something
Amos Baker
fonte