Existe uma maneira mais compacta ou pitônica de escrever a expressão booleana
a + b == c or a + c == b or b + c == a
eu vim com
a + b + c in (2*a, 2*b, 2*c)
mas isso é um pouco estranho.
Existe uma maneira mais compacta ou pitônica de escrever a expressão booleana
a + b == c or a + c == b or b + c == a
eu vim com
a + b + c in (2*a, 2*b, 2*c)
mas isso é um pouco estranho.
Respostas:
Se olharmos para o Zen de Python, enfatize o meu:
O Zen de Python, de Tim Peters
Bonito é melhor que feio.
Explícito é melhor que implícito.
Simples é melhor que complexo.
Complexo é melhor que complicado.
Flat é melhor que aninhado.
Esparso é melhor que denso.
Legibilidade conta.
Casos especiais não são especiais o suficiente para violar as regras.
Embora praticidade supere a pureza.
Os erros nunca devem passar silenciosamente.
A menos que seja explicitamente silenciado.
Diante da ambiguidade, recuse a tentação de adivinhar.
Deve haver uma - e preferencialmente apenas uma - maneira óbvia de fazê-lo.
Embora esse caminho possa não ser óbvio a princípio, a menos que você seja holandês.
Agora é melhor do que nunca.
Embora nunca seja frequentemente melhor do queagora mesmo .
Se a implementação é difícil de explicar, é uma má ideia.
Se a implementação é fácil de explicar, pode ser uma boa ideia.
Os namespaces são uma ótima idéia - vamos fazer mais!
A solução mais pitônica é aquela que é mais clara, mais simples e mais fácil de explicar:
a + b == c or a + c == b or b + c == a
Melhor ainda, você nem precisa conhecer Python para entender esse código! É isso fácil. Esta é, sem reservas, a melhor solução. Qualquer outra coisa é masturbação intelectual.
Além disso, essa também é provavelmente a solução com melhor desempenho, pois é a única dentre todas as propostas que causam curto-circuito. Se a + b == c
, apenas uma única adição e comparação for feita.
Resolvendo as três igualdades para a:
a in (b+c, b-c, c-b)
Python tem uma any
função que executa um or
em todos os elementos de uma sequência. Aqui converti sua declaração em uma tupla de 3 elementos.
any((a + b == c, a + c == b, b + c == a))
Observe que or
há um curto-circuito; portanto, se o cálculo das condições individuais for caro, talvez seja melhor manter sua construção original.
any()
e all()
curto-circuito também.
any
mesmo da execução.
any
e all
"curto-circuito" o processo de examinar o iterável que eles recebem; mas se esse iterável for uma sequência e não um gerador, ele já foi totalmente avaliado antes da ocorrência da chamada da função .
any
,-indent único a ):
na if
declaração), o que ajuda muito para facilitar a leitura quando a matemática está envolvida
Se você sabe que está lidando apenas com números positivos, isso funcionará e é bastante limpo:
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
Como eu disse, isso funciona apenas para números positivos; mas se você souber eles serão positivos, essa é uma solução IMO muito legível, mesmo diretamente no código e não em uma função.
Você pode fazer isso, o que pode fazer um pouco de computação repetida; mas você não especificou o desempenho como sua meta:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
do_stuff()
Ou sem permutations()
e a possibilidade 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()
Eu provavelmente colocaria isso, ou qualquer outra solução, em uma função. Então você pode simplesmente chamar a função no seu código.
Pessoalmente, a menos que eu precisasse de mais flexibilidade do código, usaria apenas o primeiro método na sua pergunta. É simples e eficiente. Eu ainda posso colocá-lo em uma função:
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()
Isso é bastante pitonico, e é possivelmente a maneira mais eficiente de fazer isso (a função extra chama de lado); embora você não deva se preocupar muito com o desempenho, a menos que esteja causando um problema.
Se você usará apenas três variáveis, seu método inicial:
a + b == c or a + c == b or b + c == a
Já é muito pitônico.
Se você planeja usar mais variáveis, seu método de raciocínio com:
a + b + c in (2*a, 2*b, 2*c)
É muito inteligente, mas vamos pensar no porquê. Por que isso funciona?
Bem, através de uma aritmética simples, vemos que:
a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
E isso vai ter que segurar verdade para a, b ou c, o que significa que sim, vai igualar 2*a
, 2*b
ou2*c
. Isso será verdadeiro para qualquer número de variáveis.
Portanto, uma boa maneira de escrever isso rapidamente seria simplesmente ter uma lista de suas variáveis e comparar sua soma com uma lista dos valores dobrados.
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
Dessa forma, para adicionar mais variáveis à equação, tudo o que você precisa fazer é editar sua lista de valores por 'n' novas variáveis, não escrevendo 'n' equações
a=-1
, b=-1
, c=-2
,, em seguida a+b=c
, mas a+b+c = -4
e 2*max(a,b,c)
é-2
abs()
chamadas, é Pythonic do que o trecho do OP (na verdade, eu o chamaria significativamente menos legível).
any(sum(values) == 2*x for x in values)
, dessa forma, você não precisaria fazer toda a duplicação na frente, conforme necessário.
O código a seguir pode ser usado para comparar iterativamente cada elemento com a soma dos outros, que é calculada a partir da soma de toda a lista, excluindo esse elemento.
l = [a,b,c]
any(sum(l)-e == e for e in l)
[]
suportes da segunda linha, isso vai mesmo curto-circuito como o original com or
...
any(a + b + c == 2*x for x in [a, b, c])
, muito próximo a sugestão do OP
Não tente simplificá-lo. Em vez disso, nomeie o que você está fazendo com uma função:
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):
...
Substitua a condição por algo "inteligente" que a torne mais curta, mas não a tornará mais legível. No entanto, deixar como está também não é muito legível, porque é complicado saber por que você está verificando essas três condições rapidamente. Isso torna absolutamente claro o que você está procurando.
Em relação ao desempenho, essa abordagem adiciona a sobrecarga de uma chamada de função, mas nunca sacrifica a legibilidade pelo desempenho, a menos que você encontre um gargalo que você absolutamente deve corrigir. E sempre meça, pois algumas implementações inteligentes são capazes de otimizar e incluir algumas chamadas de função em algumas circunstâncias.
Python 3:
(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...
É escalável para qualquer número de variáveis:
arr = [a,b,c,d,...]
sum(arr)/2 in arr
No entanto, em geral, concordo que, a menos que você tenha mais de três variáveis, a versão original é mais legível.
[x for x in range(pow(2,30)) if x != ((x * 2)/ pow(2,1))]
(a+b-c)*(a+c-b)*(b+c-a) == 0
Se a soma de quaisquer dois termos for igual ao terceiro termo, um dos fatores será zero, tornando o produto inteiro zero.
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
Que tal apenas:
a == b + c or abs(a) == abs(b - c)
Observe que isso não funcionará se as variáveis não forem assinadas.
Do ponto de vista da otimização de código (pelo menos na plataforma x86), essa parece ser a solução mais eficiente.
Os compiladores modernos alinham as chamadas de função abs () e evitam o teste de sinais e a ramificação condicional subsequente usando uma sequência inteligente de instruções CDQ, XOR e SUB . O código de alto nível acima será representado apenas com instruções ALU de baixa latência e alta taxa de transferência e apenas dois condicionais.
fabs()
pode ser usado para float
tipos;).
A solução fornecida por Alex Varga "a em (b + c, bc, cb)" é compacta e matematicamente bonita, mas eu não escreveria o código dessa maneira, porque o próximo desenvolvedor que chegasse não entenderia imediatamente o objetivo do código .
A solução de Mark Ransom
any((a + b == c, a + c == b, b + c == a))
é mais claro, mas não muito mais sucinto do que
a + b == c or a + c == b or b + c == a
Ao escrever um código que outra pessoa terá que procurar, ou que eu precisarei procurar muito depois, quando me esqueci do que estava pensando quando o escrevi, ser muito curto ou inteligente tende a causar mais mal do que bem. O código deve ser legível. Tão sucinto é bom, mas não tão sucinto que o próximo programador não possa entender.
A solicitação é mais compacta OU mais pitônica - tentei minha mão de forma mais compacta.
dado
import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
return x + y == z
São 2 caracteres a menos que o original
any(g(*args) for args in f((a,b,c)))
teste com:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
além disso, dado:
h = functools.partial(itertools.starmap, g)
Isso é equivalente
any(h(f((a,b,c))))
g()
você precisa definir para que isso funcione. Dado tudo isso, eu diria que é significativamente maior.
Quero apresentar o que considero a resposta mais 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))
O caso geral, não otimizado:
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
Em termos do Zen de Python, acho que as declarações enfatizadas são mais seguidas do que em outras respostas:
O Zen de Python, de Tim Peters
Bonito é melhor que feio.
Explícito é melhor que implícito.
Simples é melhor que complexo.
Complexo é melhor que complicado.
Flat é melhor que aninhado.
Esparso é melhor que denso.
Legibilidade conta.
Casos especiais não são especiais o suficiente para violar as regras.
Embora praticidade supere a pureza.
Os erros nunca devem passar silenciosamente.
A menos que seja explicitamente silenciado.
Diante da ambiguidade, recuse a tentação de adivinhar.
Deve haver uma - e preferencialmente apenas uma - maneira óbvia de fazê-lo.
Embora esse caminho possa não ser óbvio a princípio, a menos que você seja holandês.
Agora é melhor do que nunca.
Embora nunca seja frequentemente melhor do queagora mesmo .
Se a implementação é difícil de explicar, é uma má ideia.
Se a implementação é fácil de explicar, pode ser uma boa ideia.
Os namespaces são uma ótima idéia - vamos fazer mais!
Como um hábito antigo da minha programação, acho que colocar expressões complexas à direita em uma cláusula pode torná-las mais legíveis assim:
a == b+c or b == a+c or c == a+b
Plus ()
:
((a == b+c) or (b == a+c) or (c == a+b))
E também acho que o uso de várias linhas também pode fazer mais sentidos assim:
((a == b+c) or
(b == a+c) or
(c == a+b))
De uma maneira genérica,
m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
se manipular uma variável de entrada é bom para você,
c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();
se você quiser explorar usando hacks de bits, poderá usar "!", ">> 1" e "<< 1"
Evitei a divisão, embora ele permita o uso para evitar duas multiplicações para evitar erros de arredondamento. No entanto, verifique se há estouros
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