紧凑的书写方式(a + b == c或a + c == b或b + c == a)

有没有更紧凑或pythonic的方式来编写布尔expression式

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

我想出了

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

但是这有点奇怪。

如果我们看看Python的禅宗,重点是我的:

Python的禅宗,由蒂姆·彼得斯

美丽胜过丑陋。
显式比隐式更好。
简单胜于复杂。
复杂比复杂好。
平面比嵌套更好。
稀疏比密集好。
可读性计数。
特例不足以打破规则。
虽然实用性胜过纯净。
错误不应该默默通过。
除非明确沉默。
面对歧义,拒绝猜测的诱惑。
应该有一个 – 最好只有一个 – 明显的方法来做到这一点。
尽pipe这种方式一开始可能并不明显,除非你是荷兰人。
现在比从未好。
虽然从来没有比现在更好。
如果实施很难解释,这是一个坏主意。
如果实施很容易解释,这可能是一个好主意。
命名空间是一个好主意 – 让我们做更多的!

最Pythonic的解决scheme是最清晰,最简单,最容易解释的解决scheme:

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

更好的是,你甚至不需要知道Python来理解这个代码! 这很容易。 这是毫无保留的最佳解决scheme。 其他任何事情都是智力手淫。

此外,这也可能是performance最好的解决scheme,因为它是所有短路提议中唯一的解决scheme。 如果a + b == c ,那么只有一个添加和比较完成。

解决三个平等:

 a in (b+c, bc, cb) 

Python有一个any函数可以对一个序列的所有元素进行操作。 在这里我已经把你的语句转换成了一个3元组元组。

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

请注意, or短路,所以如果计算个别条件是昂贵的,保持原来的结构可能会更好。

如果你知道你只处理正数,这将工作,而且很干净:

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

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

你可以做到这一点,这可能会做一些重复的计算; 但是你没有把性能作为你的目标:

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

我可能会把这个或任何其他的解决scheme,到一个函数。 然后,你可以干净地调用你的代码中的function。

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

 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,它可能是最有效的方法(额外的function呼叫); 虽然你不应该担心太多的性能,除非它实际上是一个问题。

如果你只使用三个variables,那么你的初始方法是:

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

已经很pythonic了。

如果你打算使用更多的variables,那么你的推理方法是:

 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 。 对于任何数量的variables都是如此。

所以一个很好的方式来写这个快速的将是简单地有一个variables的列表,并检查他们的总和与一倍的价值观。

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

这样,为了在方程中增加更多的variables,你所要做的就是用n个新variables编辑你的值列表,而不是编写'n'方程

下面的代码可以用来迭代地比较每个元素和其他元素的总和,它是从整个列表的总和中计算出来的,不包括那个元素。

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

不要试图简化它。 相反,用一个函数来命名你正在做的事情:

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

将条件replace为“聪明”可能会缩短,但不会使其更具可读性。 但是,离开它的过程并不是很清晰,因为要知道为什么要一眼查看这三个条件是很棘手的。 这使得你要检查的东西非常清晰。

关于性能,这种方法确实增加了函数调用的开销,但是除非你发现了一个你必须修复的瓶颈,否则不会牺牲性能的可读性。 而且总是要衡量一下,因为在某些情况下,一些聪明的实现能够优化掉和内联一些函数调用。

Python 3:

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

它缩放到任何数量的variables:

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

但是,一般来说,我同意,除非你有三个以上的variables,否则原始版本更具可读性。

 (a+bc)*(a+cb)*(b+ca) == 0 

如果任何两项的总和等于第三项,那么其中一个因素将为零,使得整个产品为零。

如何只是:

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

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

从代码优化(至less在x86平台上)的angular度来看,这似乎是最有效的解决scheme。

现代编译器将内联两个abs()函数调用,并通过使用CDQ,XOR和SUB指令的巧妙序列来避免符号testing和随后的条件分支。 上面的高级代码将只用低延迟,高吞吐量的ALU指令和两个条件来表示。

由Alex Varga“a(b + c,bc,cb)”提供的解决scheme是紧凑且math上美观的,但我实际上不会以这种方式编写代码,因为下一位开发人员不会马上理解代码的用途。

Mark Ransom的解决scheme

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

比较清楚,但不是很简洁

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

在写代码的时候,别人不得不看一看,或者在我忘记自己写的东西的时候,我必须要看很长一段时间,太短或聪明往往会造成更多的伤害。 代码应该是可读的。 所以简洁是好的,但不是那么简洁,下一个程序员就不能理解它。

要求更紧凑或更pythonic – 我试图在更紧凑的手。

特定

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

这是比原来less2个字符

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

testing:

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

我想提出我认为是最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的禅宗而言,我认为强调的陈述比其他答案更为重要:

Python的禅宗,由蒂姆·彼得斯

美丽胜过丑陋。
显式比隐式更好。
简单胜于复杂。
复杂比复杂好。
平面比嵌套更好。
稀疏比密集好。
可读性计数。
特例不足以打破规则。
虽然实用性胜过纯净。
错误不应该默默通过。
除非明确沉默。
面对歧义,拒绝猜测的诱惑。
应该有一个 – 最好只有一个 – 明显的方法来做到这一点。
尽pipe这种方式一开始可能并不明显,除非你是荷兰人。
现在比从未好。
虽然从来没有比现在更好。
如果实施很难解释,这是一个坏主意。
如果实施很容易解释,这可能是一个好主意。
命名空间是一个好主意 – 让我们做更多的!

作为编程的一个老习惯,我认为在一个子句中放置复杂的expression式可以使它更像这样的可读性:

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

Plus ()

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

而且我认为使用多线也可以做出更多的感官:

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

以通用的方式,

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

如果,操纵一个inputvariables对你来说是OK的,

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

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

我避免了分割,尽pipe它可以避免两次乘法以避免错误。 但是,检查溢出

 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