python - true - Forma compacta de escribir(a+b== c o a+c== b o b+c== a)
true python (16)
¿Hay alguna forma más compacta o pitónica de escribir la expresión booleana?
a + b == c or a + c == b or b + c == a
se me ocurrio
a + b + c in (2*a, 2*b, 2*c)
Pero eso es un poco extraño.
¿Qué tal solo:
a == b + c or abs(a) == abs(b - c)
Tenga en cuenta que esto no funcionará si las variables no están firmadas.
Desde el punto de vista de la optimización del código (al menos en la plataforma x86), esta parece ser la solución más eficiente.
Los compiladores modernos alinearán ambas llamadas a funciones abs () y evitarán la prueba de signos y la ramificación condicional posterior mediante el uso de una secuencia inteligente de instrucciones CDQ, XOR y SUB . El código de alto nivel anterior se representará con solo instrucciones ALU de baja latencia y alto rendimiento y solo dos condicionales.
Como un viejo hábito de mi programación, creo que colocar una expresión compleja a la derecha en una cláusula puede hacerlo más legible de esta manera:
a == b+c or b == a+c or c == a+b
Más
()
:
((a == b+c) or (b == a+c) or (c == a+b))
Y también creo que usar líneas múltiples también puede tener más sentidos como este:
((a == b+c) or
(b == a+c) or
(c == a+b))
De manera genérica,
m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
si, manipular una variable de entrada está bien para ti,
c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();
si quieres explotar usando hacks de bits, puedes usar "!", ">> 1" y "<< 1"
Evité la división, aunque permite evitar dos multiplicaciones para evitar errores de redondeo. Sin embargo, verifique si hay desbordamientos
El siguiente código se puede usar para comparar iterativamente cada elemento con la suma de los demás, que se calcula a partir de la suma de la lista completa, excluyendo ese elemento.
l = [a,b,c]
any(sum(l)-e == e for e in l)
La solicitud es más compacta O más pitónica: probé con una mano más compacta.
dado
import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
return x + y == z
Esto es 2 caracteres menos que el original
any(g(*args) for args in f((a,b,c)))
prueba con:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
adicionalmente, dado:
h = functools.partial(itertools.starmap, g)
Esto es equivalente
any(h(f((a,b,c))))
La solución proporcionada por Alex Varga "a in (b + c, bc, cb)" es compacta y matemáticamente hermosa, pero en realidad no escribiría el código de esa manera porque el próximo desarrollador que viene no entendería de inmediato el propósito del código .
La solución de Mark Ransom de
any((a + b == c, a + c == b, b + c == a))
es más claro pero no mucho más sucinto que
a + b == c or a + c == b or b + c == a
Cuando escribo un código que alguien más tendrá que mirar, o que tendré que mirar mucho más tarde cuando haya olvidado lo que estaba pensando cuando lo escribí, ser demasiado corto o inteligente tiende a hacer más daño que bien. El código debe ser legible. Tan sucinto es bueno, pero no tan sucinto que el siguiente programador no pueda entenderlo.
No intentes simplificarlo. En cambio, nombra lo que estás haciendo con una función:
def any_two_sum_to_third(a, b, c):
return a + b == c or a + c == b or b + c == a
if any_two_sum_to_third(foo, bar, baz):
...
Reemplazar la condición con algo "inteligente" podría acortarlo, pero no lo hará más legible. Sin embargo, dejarlo así no es muy fácil de leer, porque es difícil saber por qué estás revisando esas tres condiciones de un vistazo. Esto hace que sea absolutamente claro lo que estás buscando.
Con respecto al rendimiento, este enfoque agrega la sobrecarga de una llamada a la función, pero nunca sacrifica la legibilidad por el rendimiento a menos que haya encontrado un cuello de botella que absolutamente debe solucionar. Y siempre mida, ya que algunas implementaciones inteligentes son capaces de optimizar y alinear algunas llamadas de función en algunas circunstancias.
Python 3:
(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...
Se escala a cualquier número de variables:
arr = [a,b,c,d,...]
sum(arr)/2 in arr
Sin embargo, en general, estoy de acuerdo en que, a menos que tenga más de tres variables, la versión original es más legible.
Python tiene una función
any
que realiza uno
or
todos los elementos de una secuencia.
Aquí he convertido tu declaración en una tupla de 3 elementos.
any((a + b == c, a + c == b, b + c == a))
Tenga en cuenta que
or
es un cortocircuito, por lo que si calcular las condiciones individuales es costoso, podría ser mejor mantener su construcción original.
Quiero presentar lo que veo como la respuesta más pitónica :
def one_number_is_the_sum_of_the_others(a, b, c):
return any((a == b + c, b == a + c, c == a + b))
El caso general, no optimizado:
def one_number_is_the_sum_of_the_others(numbers):
for idx in range(len(numbers)):
remaining_numbers = numbers[:]
sum_candidate = remaining_numbers.pop(idx)
if sum_candidate == sum(remaining_numbers):
return True
return False
En términos del Zen de Python, creo que las declaraciones enfatizadas se siguen más que de otra respuesta:
El zen de Python, por Tim Peters
Hermoso es mejor que feo.
Explícito es mejor que implícito.
Simple es mejor que complejo.
Complejo es mejor que complicado.
Plano es mejor que anidado.
Escaso es mejor que denso.
La legibilidad cuenta.
Los casos especiales no son lo suficientemente especiales como para romper las reglas.
Aunque la practicidad supera la pureza.
Los errores nunca deben pasar en silencio.
A menos que sea silenciado explícitamente.
Ante la ambigüedad, rechaza la tentación de adivinar.
Debe haber una, y preferiblemente solo una, forma obvia de hacerlo.
Aunque esa manera puede no ser obvia al principio a menos que seas holandés.
Ahora es mejor que nunca.
Aunque nunca es mejor que ahora.
Si la implementación es difícil de explicar, es una mala idea.
Si la implementación es fácil de explicar, puede ser una buena idea.
Los espacios de nombres son una gran idea, ¡hagamos más de eso!
Resolviendo las tres igualdades para a:
a in (b+c, b-c, c-b)
Si miramos el Zen de Python, el énfasis es mío:
El zen de Python, por Tim Peters
Hermoso es mejor que feo.
Explícito es mejor que implícito.
Simple es mejor que complejo.
Complejo es mejor que complicado.
Plano es mejor que anidado.
Escaso es mejor que denso.
La legibilidad cuenta.
Los casos especiales no son lo suficientemente especiales como para romper las reglas.
Aunque la practicidad supera la pureza.
Los errores nunca deben pasar en silencio.
A menos que sea silenciado explícitamente.
Ante la ambigüedad, rechaza la tentación de adivinar.
Debe haber una, y preferiblemente solo una, forma obvia de hacerlo.
Aunque esa manera puede no ser obvia al principio a menos que seas holandés.
Ahora es mejor que nunca.
Aunque nunca es mejor que ahora.
Si la implementación es difícil de explicar, es una mala idea.
Si la implementación es fácil de explicar, puede ser una buena idea.
Los espacios de nombres son una gran idea, ¡hagamos más de eso!
La solución más pitónica es la más clara, simple y fácil de explicar:
a + b == c or a + c == b or b + c == a
¡Aún mejor, ni siquiera necesita saber Python para entender este código! Es así de fácil. Esta es, sin reservas, la mejor solución. Cualquier otra cosa es la masturbación intelectual.
Además, esta es probablemente la mejor solución, ya que es la única de todas las propuestas que provocan cortocircuitos.
Si
a + b == c
, solo se realiza una única adición y comparación.
Si sabe que solo está tratando con números positivos, esto funcionará y está bastante limpio:
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
Como dije, esto solo funciona para números positivos; pero si sabe que van a ser positivos, esta es una solución IMO muy legible, incluso directamente en el código en lugar de en una función.
Podrías hacer esto, lo que podría hacer un poco de cálculo repetido; pero no especificó el rendimiento como su objetivo:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
do_stuff()
O sin
permutations()
y la posibilidad de cálculos repetidos:
if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
do_stuff()
Probablemente pondría esto, o cualquier otra solución, en una función. Entonces puede simplemente llamar limpiamente a la función en su código.
Personalmente, a menos que necesite más flexibilidad del código, simplemente usaría el primer método en su pregunta. Es simple y eficiente. Todavía podría ponerlo en una función:
def two_add_to_third(a, b, c):
return a + b == c or a + c == b or b + c == a
if two_add_to_third(a, b, c):
do_stuff()
Eso es bastante Pythonic, y es posiblemente la forma más eficiente de hacerlo (aparte de la función adicional); aunque no debería preocuparse demasiado por el rendimiento de todos modos, a menos que realmente esté causando un problema.
Si solo usará tres variables, entonces su método inicial:
a + b == c or a + c == b or b + c == a
Ya es muy pitónico.
Si planea usar más variables, entonces su método de razonamiento con:
a + b + c in (2*a, 2*b, 2*c)
Es muy inteligente pero pensemos por qué.
¿Por qué funciona esto?
Bien a través de una simple aritmética vemos que:
a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
Y esto tendrá que ser cierto para a, b o c, lo que significa que sí será igual a
2*a
,
2*b
, o
2*c
.
Esto será cierto para cualquier número de variables.
Entonces, una buena manera de escribir esto rápidamente sería simplemente tener una lista de sus variables y verificar su suma con una lista de los valores duplicados.
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
De esta manera, para agregar más variables a la ecuación, todo lo que tiene que hacer es editar su lista de valores con ''n'' nuevas variables, no escribir ecuaciones ''n''
def any_sum_of_others (*nums):
num_elements = len(nums)
for i in range(num_elements):
discriminating_map = map(lambda j: -1 if j == i else 1, range(num_elements))
if sum(n * u for n, u in zip(nums, discriminating_map)) == 0:
return True
return False
print(any_sum_of_others(0, 0, 0)) # True
print(any_sum_of_others(1, 2, 3)) # True
print(any_sum_of_others(7, 12, 5)) # True
print(any_sum_of_others(4, 2, 2)) # True
print(any_sum_of_others(1, -1, 0)) # True
print(any_sum_of_others(9, 8, -4)) # False
print(any_sum_of_others(4, 3, 2)) # False
print(any_sum_of_others(1, 1, 1, 1, 4)) # True
print(any_sum_of_others(0)) # True
print(any_sum_of_others(1)) # False
(a+b-c)*(a+c-b)*(b+c-a) == 0
Si la suma de cualquiera de los dos términos es igual al tercer término, entonces uno de los factores será cero, haciendo que todo el producto sea cero.