Devuelve booleano si el conjunto está vacío

97

Estoy luchando por encontrar una forma más limpia de devolver un valor booleano si mi conjunto está vacío al final de mi función

Tomo la intersección de dos conjuntos y quiero regresar Trueo Falsebasándome en si el conjunto resultante está vacío.

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

Mi pensamiento inicial fue hacer

return c is not None

Sin embargo, en mi intérprete puedo ver fácilmente que la afirmación volverá verdadera si c = set([])

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

También probé todo lo siguiente:

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

Ahora que he leído de la documentación que solo puedo usar and, ory notcon conjuntos vacíos para deducir un valor booleano. Hasta ahora, lo único que se me ocurre es regresar, no no c

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

Tengo la sensación de que hay una forma mucho más pitónica de hacer esto, ya que estoy luchando por encontrarla. No quiero devolver el conjunto real a una declaración if porque no necesito los valores, solo quiero saber si se cruzan.

CB
fuente
4
el conjunto vacío se considera booleano Falso equivalente si lo lanza así:bool(set([]))
woozyking
3
por cierto, pregunta seriamente bien elaborada, lo cual es notable.
Jonas Schäfer
@JonasWielicki ¡Gracias! Aprecio la respuesta, sabía que era algo por el estilo.
CB
Esta pregunta va a cumplir 5 años y nadie sugirió usarla isdisjoint. Estoy completamente sorprendido.
Adirio

Respuestas:

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

bool()Hará algo similar not not, pero más ideomático y claro.

Jonas Schäfer
fuente
7
Me opongo, escribir bool(...)cuando lo preguntas is_emptyes oscuro. No expreso la intención.
tamas.kenez
2
@ tamas.kenez Hay que admitir, sin embargo, que está más claro que not not;). (FTR: Ya había votado a favor de la respuesta de @gefeis, pero no tengo influencia en lo que OP aceptó ...)
Jonas Schäfer
109

no tan pitónico como las otras respuestas, sino matemáticas:

return len(c) == 0

Como algunos comentarios se preguntaron sobre el impacto que len(set)podría tener en la complejidad. Es O (1) como se muestra en el código fuente dado que se basa en una variable que rastrea el uso del conjunto.

static Py_ssize_t
set_len(PyObject *so)
{
    return ((PySetObject *)so)->used;
}
gefei
fuente
9
Creo que esto es mejor. Deja más claro cuál es tu intención.
arshajii
4
Me temo que esto tendrá que calcularse len(c)incluso si ces muy grande, lo cual es innecesario para verificar el vacío.
Michele De Pascalis
1
@Glaedr Creo que cpython len para estructuras de datos de uso común (es decir, lista, conjunto) es O (1) (es decir, almacenan una variable en la estructura de datos que representa la longitud)
CB
2
^ +1 @CB hice algunas pruebas en len (c) y definitivamente es una variable que representa a len porque hubo una diferencia insignificante en el tiempo de ejecución cuando el tamaño del conjunto cambió dramáticamente órdenes de magnitud.
dster77
1
@ dster77 i perfilado mi código con las dos versiones y fue significativamente más rápido cuando se compara con set()(Python 3.5.2 en Windows)
mathiasfk
23

Si lo desea return Truepara un conjunto vacío, creo que sería más claro hacerlo:

return c == set()

es decir, " ces igual a un vacío set".

(O, al revés, return c != set()).

En mi opinión, esto es más explícito (aunque menos idiomático) que confiar en la interpretación de Python de un conjunto vacío como Falseen un contexto booleano.

Jonrsharpe
fuente
2
De hecho, confiar en la interpretación de Python es una práctica muy aceptable. Siempre que se tengan en cuenta sus limitaciones.
volcán
17

Si ces un conjunto continuación, puede comprobar si está vacío haciendo: return not c.

Si cestá vacío, entonces not clo estará True.

De lo contrario, si ccontiene algún elemento not cserá False.

Simeon Visser
fuente
6

Cuando tu dices:

c is not None

En realidad, está comprobando si cy None hacen referencia al mismo objeto. Eso es lo que hace el operador "is". En Python, None es un valor nulo especial, lo que significa convencionalmente que no tiene un valor disponible. Sorta como nulo en c o java. Dado que Python internamente solo asigna un valor Ninguno usando el operador "es" para verificar si algo es Ninguno (creo que nulo) funciona, y se ha convertido en el estilo popular. Sin embargo, esto no tiene que ver con el valor de verdad del conjunto c, está comprobando que c en realidad es un conjunto en lugar de un valor nulo.

Si desea verificar si un conjunto está vacío en una declaración condicional, se convierte en un booleano en contexto, por lo que puede decir:

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

Pero si desea que se convierta en un booleano para que se almacene, simplemente puede decir:

c = set()
c_has_stuff_in_it = bool(c)
Andrew Allaire
fuente
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
fuente
0

No tan limpio como bool (c) pero fue una excusa para usar ternary.

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

Además, utilizando un poco de la misma lógica, no es necesario asignar ac a menos que lo esté utilizando para otra cosa.

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

Finalmente, supongo que desea un valor Verdadero / Falso porque va a realizar algún tipo de prueba booleana con él. Recomendaría omitir la sobrecarga de una llamada y definición de función simplemente probando donde lo necesite.

En vez de:

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

Tal vez esto:

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