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

时间:2015-08-19 02:40:12

标签: python boolean

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

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

我想出了

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

但这有点奇怪。

15 个答案:

答案 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*a2*b2*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