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

qwr*_*qwr 136 python boolean

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

a + b == c or a + c == b or b + c == a
Run Code Online (Sandbox Code Playgroud)

我想出来了

a + b + c in (2*a, 2*b, 2*c)
Run Code Online (Sandbox Code Playgroud)

但这有点奇怪.

Bar*_*rry 204

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

Tim Peters的Python之禅

美丽胜过丑陋.
显式优于隐式.
简单比复杂更好.
复杂比复杂更好.
Flat优于嵌套.
稀疏优于密集.
可读性很重要.
特殊情况不足以打破规则.
虽然实用性胜过纯洁.
错误不应该默默地传递.
除非明确沉默.
面对模棱两可,拒绝猜测的诱惑.
应该有一个 - 最好只有一个 - 明显的方法来做到这一点.
虽然这种方式起初可能并不明显,除非你是荷兰人.
现在比永远好.
虽然从来没有经常好过正确的现在.
如果实施很难解释,这是一个坏主意.
如果实现很容易解释,那可能是个好主意.
命名空间是一个很棒的主意 - 让我们做更多的事情吧!

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

a + b == c or a + c == b or b + c == a
Run Code Online (Sandbox Code Playgroud)

更好的是,你甚至不需要知道Python来理解这段代码!就这么简单.这是毫无保留的最佳解决方案.其他任何东西都是智力手淫.

此外,这也可能是性能最佳的解决方案,因为它是所有短路提案中唯一的解决方案.如果a + b == c,只进行一次添加和比较.

  • 更好的是,抛出一些括号,使意图清晰. (11认同)
  • 意图已经很清楚,没有括号.括号会让你更难阅读 - 为什么作者在优先权已涵盖这一点时使用括号? (3认同)

Ale*_*rga 101

解决a的三个等式:

a in (b+c, b-c, c-b)
Run Code Online (Sandbox Code Playgroud)

  • 阅读此代码的任何人都可能会诅咒你"聪明". (23认同)
  • @SilvioMayolo原作同样如此 (5认同)
  • 唯一的问题是副作用.如果b或c是更复杂的表达式,它们将被多次运行. (4认同)
  • @Kroltan我的观点是我实际上回答了他的问题,要求提供"更紧凑"的表示.请参阅:https://en.m.wikipedia.org/wiki/Short-circuit_evaluation (3认同)

Mar*_*som 54

Python有一个any函数可以or对序列的所有元素进行处理.在这里,我已将您的语句转换为3元素元组.

any((a + b == c, a + c == b, b + c == a))
Run Code Online (Sandbox Code Playgroud)

请注意,这or是短路的,因此如果计算单个条件很昂贵,那么保留原始构造可能会更好.

  • @ TigerhawkT3虽然不是这种情况; 在元组存在之前将对三个表达式进行求值,并且在"any"甚至运行之前元组将存在. (42认同)
  • 啊,我明白了.我想这只是在那里有一个生成器或类似的懒惰迭代器. (13认同)
  • `any`和`all`"短路"*检查*他们给出的迭代的过程; 但是如果那个iterable是一个序列而不是一个生成器,那么它在函数调用发生之前就已经被完全评估了*. (4认同)
  • `any()`和`all()`也是短路. (2认同)

Cyp*_*ase 40

如果你知道你只处理正数,这将是有效的,并且非常干净:

a, b, c = sorted((a, b, c))
if a + b == c:
    do_stuff()
Run Code Online (Sandbox Code Playgroud)

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

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

from itertools import permutations

if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
    do_stuff()
Run Code Online (Sandbox Code Playgroud)

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

if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
    do_stuff()
Run Code Online (Sandbox Code Playgroud)

我可能会把这个或任何其他解决方案放入一个函数中.然后你可以干净地调用代码中的函数.

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

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()
Run Code Online (Sandbox Code Playgroud)

这是非常好的Pythonic,它很可能是最有效的方法(额外的函数调用); 虽然你不应该过多担心性能,除非它实际上引起了一个问题.

  • 哦,快点."_如果你知道你只处理正数_,这将有效,并且相当干净".所有其他人都适用于任何数字,但如果你知道你只处理正数_,那么最上面的数字是非常易读的/ Pythonic IMO. (3认同)

Tha*_*ell 17

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

a + b == c or a + c == b or b + c == a
Run Code Online (Sandbox Code Playgroud)

已经非常pythonic.

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

a + b + c in (2*a, 2*b, 2*c)
Run Code Online (Sandbox Code Playgroud)

很聪明,但我们想想为什么.为什么这样做?
通过一些简单的算法,我们看到:

a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
Run Code Online (Sandbox Code Playgroud)

而这将是成立的,无论对于A,B或C,这意味着是的,它会等于2*a,2*b2*c.对于任何数量的变量都是如此.

因此,快速编写此代码的一种好方法是简单地列出变量列表,并根据doubled值列表检查它们的总和.

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

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

  • 怎么样的'a = -1`,`b = -1`,`c = -2`,然后`a + b = c`,但是'a + b + c = -4`和'2*max(a ,b,c)`是`-2` (4认同)
  • 用六个`abs()`调用它后,它是Pythonic而不是OP的片段(我实际上称它的可读性差得多). (2认同)

Arc*_*num 12

以下代码可用于迭代地比较每个元素与其他元素的总和,这是从整个列表的总和计算的,不包括该元素.

 l = [a,b,c]
 any(sum(l)-e == e for e in l)
Run Code Online (Sandbox Code Playgroud)

  • 很好:)我想如果你从第二行删除`[]`括号,这甚至会像原来的`或'那样短路... (2认同)

Jac*_*ack 10

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

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):
  ...
Run Code Online (Sandbox Code Playgroud)

用"聪明"替换条件可能会使其更短,但不会使其更具可读性.然而,离开它的方式也不是很易读,因为知道你为什么一眼就检查这三个条件是很棘手的.这使得您正在检查的内容非常清晰.

关于性能,这种方法确实增加了函数调用的开销,但从不牺牲性能的可读性,除非你找到了一个绝对必须修复的瓶颈.并且总是测量,因为一些聪明的实现能够在某些情况下优化并内联一些函数调用.

  • 来自FP学院的事情,我几乎不得不完全不同意,并说明一个好的命名单行函数是提高你可以找到的可读性的最佳工具.只要您执行某些操作的步骤没有立即清楚地表明您正在做什么,就可以创建一个函数,因为该函数的名称允许您指定*what*比任何注释更好. (5认同)

Vit*_*nko 9

Python 3:

(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...
Run Code Online (Sandbox Code Playgroud)

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

arr = [a,b,c,d,...]
sum(arr)/2 in arr
Run Code Online (Sandbox Code Playgroud)

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

  • 由于浮点舍入错误,这会返回某些输入的错误结果. (3认同)
  • 除以2只是将指数减1,因此对于任何小于2 ^ 53的整数(python中float的小数部分)都是准确的,对于较大的整数,你可以使用[decimal](https: //docs.python.org/3/library/decimal.html).例如,要检查小于2 ^ 30的整数运行`[x表示范围内的x(pow(2,30)),如果x!=((x*2)/ pow(2,1))] (3认同)

mbe*_*ish 6

(a+b-c)*(a+c-b)*(b+c-a) == 0
Run Code Online (Sandbox Code Playgroud)

如果任意两个项的总和等于第三项,那么其中一个因子将为零,使整个产品为零.


Igo*_*cki 6

怎么样:

a == b + c or abs(a) == abs(b - c)
Run Code Online (Sandbox Code Playgroud)

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

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

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