是否有更紧凑或pythonic的方式来编写布尔表达式
a + b == c or a + c == b or b + c == a
我想出了
a + b + c in (2*a, 2*b, 2*c)
但这有点奇怪。
答案 0 :(得分:204)
如果我们看一下Python的禅,强调我的:
Python的禅宗,蒂姆·彼得斯
美丽胜过丑陋 明确比隐含更好 简单比复杂更好。
复杂比复杂更好 扁平比嵌套好。
稀疏比密集更好 可读性很重要。
特殊情况不足以打破规则 虽然实用性超过了纯度 错误绝不应该默默无闻 除非明确沉默。
面对模棱两可,拒绝猜测的诱惑 应该有一个 - 最好只有一个 - 显而易见的方法。
虽然这种方式起初可能并不明显,除非你是荷兰人 现在总比没有好。
虽然现在永远不会比正确更好 如果实施难以解释,那就不错了。
如果实施很容易解释,那可能是个好主意。
命名空间是一个很棒的主意 - 让我们做更多的事情!
最Pythonic解决方案是最清晰,最简单,最容易解释的解决方案:
a + b == c or a + c == b or b + c == a
更好的是,您甚至不需要了解Python就能理解这段代码! 很容易。这是毫无保留的最佳解决方案。其他任何事情都是智力手淫。
此外,这也可能是性能最佳的解决方案,因为它是所有短路提案中唯一的解决方案。如果a + b == c
,则只进行一次添加和比较。
答案 1 :(得分:101)
为a:
解决三个等式a in (b+c, b-c, c-b)
答案 2 :(得分:54)
Python有一个any
函数,它对序列的所有元素执行or
。在这里,我已将您的陈述转换为3元素元组。
any((a + b == c, a + c == b, b + c == a))
请注意or
是短路的,因此如果计算个别条件很昂贵,那么保留原始构造可能会更好。
答案 3 :(得分:40)
如果你知道你只处理正数,这将有效,并且相当干净:
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,它可能是最有效的方式(额外的功能调用);虽然你不应该过分关注性能,除非它实际上导致了问题。
答案 4 :(得分:17)
如果你只使用三个变量,那么你的初始方法是:
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*a
,2*b
或2*c
。对于任何数量的变量都是如此。
因此,快速编写此代码的一种好方法是简单地列出变量列表,并根据doubled值列表检查它们的总和。
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
这样,要在等式中添加更多变量,您只需要通过'n'个新变量编辑值列表,而不是写'n'个等式
答案 5 :(得分:12)
以下代码可用于迭代地比较每个元素与其他元素的总和,这是从整个列表的总和计算出来的,不包括该元素。
l = [a,b,c]
any(sum(l)-e == e for e in l)
答案 6 :(得分:10)
不要试图简化它。相反, 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):
...
用某种东西取代条件"聪明"可能会缩短它,但它不会让它更具可读性。然而,离开它的方式并不是非常易读,因为知道为什么你一眼就能检查这三个条件是很棘手的。这使您非常清楚自己要检查的内容。
关于性能,这种方法确实增加了函数调用的开销,但从不牺牲性能的可读性,除非你发现了一个绝对必须修复的瓶颈。并且总是测量,因为一些聪明的实现能够在某些情况下优化并内联一些函数调用。
答案 7 :(得分:9)
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
但是,一般情况下我同意,除非你有三个以上的变量,否则原始版本更具可读性。
答案 8 :(得分:6)
(a+b-c)*(a+c-b)*(b+c-a) == 0
如果任意两个项的总和等于第三项,那么其中一个因子将为零,使整个产品为零。
答案 9 :(得分:6)
如何:
a == b + c or abs(a) == abs(b - c)
请注意,如果变量是无符号的,这将不起作用。
从代码优化的角度来看(至少在x86平台上),这似乎是最有效的解决方案。
现代编译器将内联两个abs()函数调用,并使用clever sequence of CDQ, XOR, and SUB instructions来避免符号测试和后续条件分支。因此,上述高级代码仅使用低延迟,高吞吐量ALU指令和两个条件表示。
答案 10 :(得分:4)
Alex Varga提供的解决方案“a in(b + c,bc,cb)”是紧凑的,数学上很漂亮,但我实际上不会这样写代码,因为下一个开发人员不会立即理解目的代码。
Mark Ransom的解决方案
any((a + b == c, a + c == b, b + c == a))
比
更清晰但更简洁a + b == c or a + c == b or b + c == a
在编写其他人必须要查看的代码时,或者当我忘记写作时我想到的内容时,我将不得不长时间看一下,太短或太聪明往往会造成更多伤害比好。代码应该是可读的。所以简洁是好的,但不是那么简洁,以至于下一个程序员无法理解它。
答案 11 :(得分:2)
请求更紧凑或更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))))
答案 12 :(得分:1)
我想呈现我认为最 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的Zen而言,我认为强调的陈述比其他答案要多:
Python的禅宗,蒂姆·彼得斯
美丽胜过丑陋 明确胜过隐含。
简单比复杂更好。
复杂比复杂更好 扁平比嵌套好。
稀疏比密集更好 可读性很重要。
特殊情况不足以打破规则 虽然实用性超过了纯度 错误绝不应该默默无闻 除非明确沉默。
面对模棱两可,拒绝猜测的诱惑 应该有一个 - 最好只有一个 - 明显的方式来做到这一点 虽然这种方式起初可能并不明显,除非你是荷兰人 现在总比没有好。
虽然现在永远不会比正确更好 如果实施很难解释,那是个坏主意 如果实施很容易解释,那可能是个好主意 命名空间是一个很好的主意 - 让我们做更多的事情!
答案 13 :(得分:0)
以通用方式,
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”
我避免了划分虽然它允许使用避免两次乘法以避免舍入错误。但是,请检查溢出
答案 14 :(得分:0)
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