是否有更紧凑或Pythonic的方式来编写布尔表达式
a + b == c or a + c == b or b + c == a
我想出了
a + b + c in (2*a, 2*b, 2*c)
但这有点奇怪。
是否有更紧凑或Pythonic的方式来编写布尔表达式
a + b == c or a + c == b or b + c == a
我想出了
a + b + c in (2*a, 2*b, 2*c)
但这有点奇怪。
Answers:
如果我们看一下Python的Zen,请强调一下:
提姆·彼得斯(Tim Peters)撰写的《 Python之禅》
美丽胜于丑陋。
显式胜于隐式。
简单胜于复杂。
复杂胜于复杂。
扁平比嵌套更好。
稀疏胜于密集。
可读性很重要。
特殊情况还不足以打破规则。
尽管实用性胜过纯度。
错误绝不能默默传递。
除非明确地保持沉默。
面对模棱两可的想法,拒绝猜测的诱惑。
应该有一种-最好只有一种-显而易见的方法。
尽管除非您是荷兰人,否则一开始这种方式可能并不明显。
现在总比没有好。
虽然从来没有比这更好正确的现在。
如果实现难以解释,那是个坏主意。
如果实现易于解释,则可能是个好主意。
命名空间是一个很棒的主意-让我们做更多这些吧!
最Python化的解决方案是最清晰,最简单和最容易解释的解决方案:
a + b == c or a + c == b or b + c == a
更好的是,您甚至不需要了解Python就能理解此代码!就这么简单。这是毫无保留的最佳解决方案。其他一切都是智力上的自慰。
此外,这可能也是性能最佳的解决方案,因为它是所有短路建议中的唯一解决方案。如果为a + b == c
,则仅进行一次加法和比较。
解决以下三个等式:
a in (b+c, b-c, c-b)
Python具有对序列的所有元素any
执行的功能or
。在这里,我已经将您的陈述转换为3元素元组。
any((a + b == c, a + c == b, b + c == a))
请注意,这or
是短路的,因此,如果计算单个条件的成本很高,则最好保留原始结构。
any()
和all()
短路。
any
偶数运行之前就存在。
any
并且all
“短路” 检查给出的可迭代项的过程;但是,如果该可迭代对象是序列而不是生成器,则在函数调用发生之前已经对其进行了全面评估。
any
双缩进,):
在if
语句中进行单缩进),这在涉及数学时有助于提高可读性
如果您知道只处理正数,则可以使用,并且很干净:
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
而这将不得不为任何一个,b或c保持为真,这意味着是的,它会等于2*a
,2*b
或2*c
。任何数量的变量都是如此。
因此,快速编写此代码的一种好方法是只包含一个变量列表,并对照一倍的值列表检查它们的总和。
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
这样,要将更多变量添加到方程式中,您要做的就是通过“ n”个新变量来编辑值列表,而不是编写“ n”个方程式
a=-1
,b=-1
,c=-2
,然后a+b=c
,但a+b+c = -4
并2*max(a,b,c)
是-2
abs()
电话之后,它比起OP的片段是Python风格的(我实际上称其可读性差得多)。
any(sum(values) == 2*x for x in values)
,这样您就不必在必要时预先进行所有加倍操作。
以下代码可用于将每个元素与其他元素的总和进行迭代比较,这是根据整个列表的总和(不包括该元素)计算得出的。
l = [a,b,c]
any(sum(l)-e == e for e in l)
[]
从第二行中除去括号,这甚至会与原始行短路,or
...
any(a + b + c == 2*x for x in [a, b, c])
与OP的建议非常接近
不要尝试简化它。取而代之的是使用函数命名:
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):
...
将条件替换为“聪明”可能会使它更短,但不会使其更具可读性。但是,如何保留它也不是很容易理解,因为要知道为什么要一眼检查这三个条件是很棘手的。这使您可以清楚地确定要检查的内容。
关于性能,这种方法的确增加了函数调用的开销,但是除非您发现了绝对必须解决的瓶颈,否则不要牺牲性能的可读性。并始终进行测量,因为某些巧妙的实现能够在某些情况下优化并内联某些函数调用。
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
但是,总的来说,我同意除非您拥有三个以上的变量,否则原始版本更具可读性。
[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
如果任意两项的总和等于第三项,则其中一个因子将为零,从而使整个乘积为零。
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
怎么样:
a == b + c or abs(a) == abs(b - c)
请注意,如果变量是无符号的,这将不起作用。
从代码优化的角度(至少在x86平台上),这似乎是最有效的解决方案。
现代编译器将内联两个abs()函数调用,并通过使用巧妙的CDQ,XOR和SUB指令序列来避免符号测试和随后的条件分支。因此,上面的高级代码将仅由低延迟,高吞吐量的ALU指令和仅两个条件表示。
fabs()
可以用于float
类型;)。
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
当编写代码时,别人不得不去看,或者当我忘记了编写代码时的想法时,我将不得不花很长时间去看,太短或太聪明往往弊大于利。代码应可读。简洁是件好事,但不是那么简洁,以致下一个程序员无法理解。
请求的是更紧凑或更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))))
g()
为了使此功能正常运行,您还需要定义函数的小问题。考虑到所有这些,我想说它要大得多。
我想介绍一下我认为是最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而言,我认为强调的陈述比其他答案更受关注:
提姆·彼得斯(Tim Peters)撰写的《 Python之禅》
美丽胜于丑陋。
显式胜于隐式。
简单胜于复杂。
复杂胜于复杂。
扁平比嵌套更好。
稀疏胜于密集。
可读性很重要。
特殊情况还不足以打破规则。
尽管实用性胜过纯度。
错误绝不能默默传递。
除非明确地保持沉默。
面对模棱两可的想法,拒绝猜测的诱惑。
应该有一种-最好只有一种-显而易见的方法。
尽管除非您是荷兰人,否则一开始这种方式可能并不明显。
现在总比没有好。
虽然从来没有比这更好正确的现在。
如果实现难以解释,那是个坏主意。
如果实现易于解释,则可能是个好主意。
命名空间是一个很棒的主意-让我们做更多这些吧!
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