简洁的写法(a + b == c or a + c == b or b + c == a)

Compact way of writing (a + b == c or a + c == b or b + c == a)

是否有更紧凑或pythonic的方式来编写布尔表达式

a + b == c or a + c == b or b + c == a

我想出了

a + b + c in (2*a, 2*b, 2*c)

但这有点奇怪。

如果你知道你只处理正数,这会起作用,而且非常干净:

a, b, c = sorted((a, b, c))
if a + b == c:
    do_stuff()

正如我所说,这只适用于正数;但是如果你知道他们会是积极的,这是一个非常可读的解决方案 IMO,甚至直接在代码中而不是在函数中。

你可以这样做,这可能会做一些重复计算;但您没有将性能指定为您的目标:

from itertools import permutations

if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
    do_stuff()

或者没有permutations()和重复计算的可能性:

if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
    do_stuff()

我可能会将这个或任何其他解决方案放入一个函数中。然后你就可以在你的代码中干净利落地调用这个函数了。

就个人而言,除非我需要更多的代码灵活性,否则我只会在您的问题中使用第一种方法。它简单高效。我仍然可以将它放入一个函数中:

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

这很 Pythonic,而且它很可能是最有效的方法(除了额外的函数调用);尽管无论如何您都不应该太担心性能,除非它确实导致了问题。

如果您只使用三个变量,那么您的初始方法是:

a + b == c or a + c == b or b + c == a

已经很pythonic了。

如果您计划使用更多变量,那么您的推理方法是:

a + b + c in (2*a, 2*b, 2*c)

非常聪明,但让我们想想为什么。为什么这行得通?
通过一些简单的算术我们可以看出:

a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c

这必须适用于 a、b 或 c,这意味着是的,它将等于 2*a2*b2*c。对于任意数量的变量都是如此。

因此,快速编写此代码的一个好方法是简单地列出您的变量,然后根据双倍值列表检查它们的总和。

values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])

这样,要在等式中添加更多变量,您只需通过 'n' 新变量编辑值列表,而不是编写 'n' 等式

请求更紧凑或更 pythonic - 我尝试了更紧凑。

给出

import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
    return x + y == z

比原来少了2个字

any(g(*args) for args in f((a,b,c)))

测试:

assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)

此外,给定:

h = functools.partial(itertools.starmap, g)

这是等价的

any(h(f((a,b,c))))

Python 有一个 any 函数,它对序列的所有元素执行 or。在这里,我已将您的语句转换为 3 元素元组。

any((a + b == c, a + c == b, b + c == a))

请注意 or 是短路的,因此如果计算各个条件的成本很高,最好保留您的原始构造。

求解a的三个等式:

a in (b+c, b-c, c-b)

一般来说,

m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();

如果您可以操作输入变量,

c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();

如果你想利用位黑客,你可以使用“!”,“>> 1”和“<< 1”

我避免了除法,尽管它可以避免两次乘法以避免舍入错误。但是,检查溢出

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

如果任意两项之和等于第三项,则其中一个因式为零,使得整个乘积为零。

如果我们看Python的禅,强调我的:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

最 Pythonic 的解决方案是最清晰、最简单、最容易解释的解决方案:

a + b == c or a + c == b or b + c == a

更好的是,您甚至不需要知道 Python 就能理解这段代码! 很简单。毫无保留,这是最好的解决方案。别的什么都是智力自慰

此外,这也可能是性能最好的解决方案,因为它是所有短路提案中唯一的一个。如果a + b == c,只做一次加法比较。

以下代码可用于迭代地将每个元素与其他元素的总和进行比较,其他元素的总和是根据整个列表的总和计算得出的,不包括该元素。

 l = [a,b,c]
 any(sum(l)-e == e for e in l)

A​​lex Varga "a in (b+c, b-c, c-b)" 提供的解决方案紧凑且数学上很漂亮,但实际上我不会那样编写代码,因为下一位开发人员不会立即理解代码的用途。

Mark Ransom 的

解决方案
any((a + b == c, a + c == b, b + c == a))

更清晰,但也没有更简洁
a + b == c or a + c == b or b + c == a

当我写的代码别人不得不看,或者我写了很久以后我要看的时候我忘记了我写的时候是怎么想的,太短或太聪明往往会做弊大于利。代码应该是可读的。这么简洁就好,但不能简洁到下一个程序员看不懂。

怎么样:

a == b + c or abs(a) == abs(b - c)

请注意,如果变量是无符号的,这将不起作用。

从代码优化的角度来看(至少在 x86 平台上)这似乎是最有效的解决方案。

现代编译器将内联 abs() 函数调用,并通过使用 clever sequence of CDQ, XOR, and SUB instructions 避免符号测试和后续条件分支。因此,上面的高级代码将只用低延迟、高吞吐量的 ALU 指令和两个条件来表示。

Python 3:

(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...

它可以扩展到任意数量的变量:

arr = [a,b,c,d,...]
sum(arr)/2 in arr

不过,总的来说我同意,除非你有三个以上的变量,否则原始版本更具可读性。

不要试图简化它。相反,name 你正在用一个函数做什么:

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):
  ...

将条件替换为 "clever" 可能会使它更短,但不会使其更具可读性。然而,让它保持原样也不是很可读,因为一眼就知道 为什么 你要检查这三个条件是很棘手的。这绝对 crystal 清楚您要检查的内容。

关于性能,这种方法确实增加了函数调用的开销,但绝不会为了性能而牺牲可读性,除非您发现了绝对必须解决的瓶颈。并始终衡量,因为一些聪明的实现能够在某些情况下优化并内联一些函数调用。

作为我编程的一个老习惯,我认为将复杂的表达式放在子句的右侧可以使其更具可读性,如下所示:

a == b+c or b == a+c or c == a+b

加上():

((a == b+c) or (b == a+c) or (c == a+b))

而且我认为使用多行也可以像这样更有意义:

((a == b+c) or 
 (b == a+c) or 
 (c == a+b))

我想展示我认为最 pythonic 答案:

def one_number_is_the_sum_of_the_others(a, b, c):
    return any((a == b + c, b == a + c, c == a + b))

一般情况,未优化:

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 

就 Python 的禅而言,我认为强调的陈述比其他答案更受关注:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!