有没有更紧凑或更符合Python风格的写布尔表达式的方法?
a + b == c or a + c == b or b + c == a
我想出了
a + b + c in (2*a, 2*b, 2*c)
但那有点奇怪。
有没有更紧凑或更符合Python风格的写布尔表达式的方法?
a + b == c or a + c == b or b + c == a
我想出了
a + b + c in (2*a, 2*b, 2*c)
但那有点奇怪。
如果我们看一下“Python之禅”,强调如下:
《Python之禅》,作者Tim Peters
优美胜于丑陋。
显式胜于隐式。
简洁胜于复杂。
复杂胜于凌乱。
扁平胜于嵌套。
疏远胜于密集。
可读性很重要。
特殊情况并不足以打破规则。
虽然实用性比纯粹性更重要。
错误不应该悄无声息地传递。
除非有意地保持沉默。
面对模棱两可,拒绝猜测的诱惑。
最好只有一种明显的方法来做事情。
尽管这种方法可能不会一开始就显而易见,除非你是荷兰人。
现在开始总比永远不开始要好。
尽管永远比现在好。
如果实现很难解释,那么这是一个坏主意。
如果实现很容易解释,那么这可能是一个好主意。
命名空间是一个伟大的想法——让我们做更多这样的事情!
最Pythonic的解决方案是最清晰、最简单、最易于解释的方案:
a + b == c or a + c == b or b + c == a
更好的是,您甚至不需要了解Python就能理解这段代码!它非常容易。毫无保留地说,这是最佳解决方案。其他任何方案都是知识上的妄想。
此外,这很可能也是最佳表现的解决方案,因为它是所有提案中唯一的短路。如果a + b == c
,只需进行一次加法和比较即可。
解三元一次方程组,求得a的值:
a in (b+c, b-c, c-b)
Python有一个any
函数,它对序列的所有元素进行逻辑“或”操作。在这里,我将您的语句转换为一个由三个元素组成的元组。
any((a + b == c, a + c == b, b + c == a))
请注意,or
是短路的,因此如果计算各个条件的成本很高,最好保留原始结构。any()
和all()
也会短路。 - TigerhawkT3any
运行之前就已经存在了。 - pokeany
和all
在处理给定的可迭代对象时会进行"短路",不过如果该可迭代对象是一个序列而非生成器,那么在函数调用发生前它已经被完全评估。 - Karl Knechtel如果你知道你只处理正数,这将有效且非常简洁:
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
就像我之前所说,这个方法只适用于正数;但是如果你知道它们将是正数,那么我认为这是一个非常易读的解决方案,甚至可以直接写在代码中而不是写成一个函数。
你可以尝试这样做,但可能会进行一些重复计算;但既然你没有将性能作为目标,那就无妨:
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
已经非常符合Python风格。
如果您计划使用更多的变量,则需要调整您的思考方式:
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
。这对于任何数量的变量都是正确的。
因此,快速编写此内容的好方法是简单地列出您的变量,并将它们的总和与加倍值列表进行比较。
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
。 - Eric Renoufabs()
调用后,它比OP的片段更具Pythonic风格(实际上我认为它的可读性显著降低了)。 - TigerhawkT3这不太符合 Python 的风格。
- TigerhawkT3any(sum(values) == 2*x for x in values)
,这样您就不必一开始就把所有的加倍都做完,只有在必要时才会执行。 - Barry l = [a,b,c]
any(sum(l)-e == e for e in l)
[]
括号,这将像原始代码一样使用 or
进行短路运算... - psmearsany(a + b + c == 2*x for x in [a, b, c])
,与原帖作者的建议非常接近。 - njzk2不要试图简化它。相反,通过函数命名来描述你正在做什么:
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))]
。 - Vitalii Fedorenko(a+b-c)*(a+c-b)*(b+c-a) == 0
如果任意两个术语的和等于第三个术语,则其中一个因数将为零,从而使整个乘积为零。
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
没有什么不同。 - mbeckish只是这样怎么样:
a == b + c or abs(a) == abs(b - c)
fabs()
可以用于float
类型 ;)。 - shA.t