问题:简洁的书写方式(a + b == c或a + c == b或b + c == a)
是否有更紧凑或Pythonic的方式来编写布尔表达式
a + b == c or a + c == b or b + c == a
我想出了
a + b + c in (2*a, 2*b, 2*c)
但这有点奇怪。
Is there a more compact or pythonic way to write the boolean expression
a + b == c or a + c == b or b + c == a
I came up with
a + b + c in (2*a, 2*b, 2*c)
but that is a little strange.
回答 0
如果我们看一下Python的Zen,请强调一下:
提姆·彼得斯(Tim Peters)撰写的《 Python之禅》
美丽胜于丑陋。
显式胜于隐式。
简单胜于复杂。
复杂胜于复杂。
扁平比嵌套更好。
稀疏胜于密集。
可读性很重要。
特殊情况还不足以打破规则。
尽管实用性胜过纯度。
错误绝不能默默传递。
除非明确地保持沉默。
面对模棱两可的想法,拒绝猜测的诱惑。
应该有一种-最好只有一种-显而易见的方法。
尽管除非您是荷兰人,否则一开始这种方式可能并不明显。
现在总比没有好。
虽然从来没有比这更好正确的现在。
如果实现难以解释,那是个坏主意。
如果实现易于解释,则可能是个好主意。
命名空间是一个很棒的主意-让我们做更多这些吧!
最Python化的解决方案是最清晰,最简单和最容易解释的解决方案:
a + b == c or a + c == b or b + c == a
更好的是,您甚至不需要了解Python就能理解此代码!就这么简单。这是毫无保留的最佳解决方案。其他一切都是智力上的自慰。
此外,这可能也是性能最佳的解决方案,因为它是所有短路建议中的唯一解决方案。如果为a + b == c
,则仅进行一次加法和比较。
If we look at the Zen of Python, emphasis mine:
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one– and preferably only one –obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea — let’s do more of those!
The most Pythonic solution is the one that is clearest, simplest, and easiest to explain:
a + b == c or a + c == b or b + c == a
Even better, you don’t even need to know Python to understand this code! It’s that easy. This is, without reservation, the best solution. Anything else is intellectual masturbation.
Furthermore, this is likely the best performing solution as well, as it is the only one out of all the proposals that short circuits. If a + b == c
, only a single addition and comparison is done.
回答 1
解决以下三个等式:
a in (b+c, b-c, c-b)
Solving the three equalities for a:
a in (b+c, b-c, c-b)
回答 2
Python具有对序列的所有元素any
执行的功能or
。在这里,我已经将您的陈述转换为3元素元组。
any((a + b == c, a + c == b, b + c == a))
请注意,这or
是短路的,因此,如果计算单个条件的成本很高,则最好保留原始结构。
Python has an any
function that does an or
on all the elements of a sequence. Here I’ve converted your statement into a 3-element tuple.
any((a + b == c, a + c == b, b + c == a))
Note that or
is short circuiting, so if calculating the individual conditions is expensive it might be better to keep your original construct.
回答 3
如果您知道只处理正数,则可以使用,并且很干净:
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的,并且可能是最有效的方式(除了额外的函数调用);尽管您无论如何也不必太担心性能,除非它确实引起了问题。
If you know you’re only dealing with positive numbers, this will work, and is pretty clean:
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
As I said, this only works for positive numbers; but if you know they’re going to be positive, this is a very readable solution IMO, even directly in the code as opposed to in a function.
You could do this, which might do a bit of repeated computation; but you didn’t specify performance as your goal:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
do_stuff()
Or without permutations()
and the possibility of repeated computations:
if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
do_stuff()
I would probably put this, or any other solution, into a function. Then you can just cleanly call the function in your code.
Personally, unless I needed more flexibility from the code, I would just use the first method in your question. It’s simple and efficient. I still might put it into a function:
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()
That’s pretty Pythonic, and it’s quite possibly the most efficient way to do it (the extra function call aside); although you shouldn’t worry too much about performance anyway, unless it’s actually causing an issue.
回答 4
如果仅使用三个变量,则使用初始方法:
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”个方程式
If you will only be using three variables then your initial method:
a + b == c or a + c == b or b + c == a
Is already very pythonic.
If you plan on using more variables then your method of reasoning with:
a + b + c in (2*a, 2*b, 2*c)
Is very smart but lets think about why. Why does this work?
Well through some simple arithmetic we see that:
a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
And this will have to hold true for either a,b, or c, meaning that yes it will equal 2*a
, 2*b
, or 2*c
. This will be true for any number of variables.
So a good way to write this quickly would be to simply have a list of your variables and check their sum against a list of the doubled values.
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
This way, to add more variables into the equation all you have to do is edit your values list by ‘n’ new variables, not write ‘n’ equations
回答 5
以下代码可用于将每个元素与其他元素的总和进行迭代比较,这是根据整个列表的总和(不包括该元素)计算得出的。
l = [a,b,c]
any(sum(l)-e == e for e in l)
The following code can be used to iteratively compare each element with the sum of the others, which is computed from sum of the whole list, excluding that element.
l = [a,b,c]
any(sum(l)-e == e for e in l)
回答 6
不要尝试简化它。取而代之的是使用函数命名:
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):
...
将条件替换为“聪明”可能会使它更短,但不会使其更具可读性。但是,如何保留它也不是很容易理解,因为要知道为什么要一眼检查这三个条件是很棘手的。这使您可以清楚地确定要检查的内容。
关于性能,这种方法的确增加了函数调用的开销,但是除非您发现了绝对必须解决的瓶颈,否则不要牺牲性能的可读性。并始终进行测量,因为某些巧妙的实现能够在某些情况下优化并内联某些函数调用。
Don’t try and simplify it. Instead, name what you’re doing with a function:
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):
...
Replace the condition with something “clever” might make it shorter, but it won’t make it more readable. Leaving it how it is isn’t very readable either however, because it’s tricky to know why you’re checking those three conditions at a glance. This makes it absolutely crystal clear what you’re checking for.
Regarding performance, this approach does add the overhead of a function call, but never sacrifice readability for performance unless you’ve found a bottleneck you absolutely must fix. And always measure, as some clever implementations are capable of optimizing away and inlining some function calls in some circumstances.
回答 7
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
但是,总的来说,我同意除非您拥有三个以上的变量,否则原始版本更具可读性。
Python 3:
(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...
It scales to any number of variables:
arr = [a,b,c,d,...]
sum(arr)/2 in arr
However, in general I agree that unless you have more than three variables, the original version is more readable.
回答 8
(a+b-c)*(a+c-b)*(b+c-a) == 0
如果任意两项的总和等于第三项,则其中一个因子将为零,从而使整个乘积为零。
(a+b-c)*(a+c-b)*(b+c-a) == 0
If the sum of any two terms is equal to the third term, then one of the factors will be zero, making the entire product zero.
回答 9
怎么样:
a == b + c or abs(a) == abs(b - c)
请注意,如果变量是无符号的,这将不起作用。
从代码优化的角度(至少在x86平台上),这似乎是最有效的解决方案。
现代编译器将内联两个abs()函数调用,并通过使用巧妙的CDQ,XOR和SUB指令序列来避免符号测试和随后的条件分支。因此,上面的高级代码将仅由低延迟,高吞吐量的ALU指令和仅两个条件表示。
How about just:
a == b + c or abs(a) == abs(b - c)
Note that this won’t work if variables are unsigned.
From the viewpoint of code optimization (at least on x86 platform) this seems to be the most efficient solution.
Modern compilers will inline both abs() function calls and avoid sign testing and subsequent conditional branch by using a clever sequence of CDQ, XOR, and SUB instructions. The above high-level code will thus be represented with only low-latency, high-throughput ALU instructions and just two conditionals.
回答 10
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
当编写代码时,别人不得不去看,或者当我忘记了编写代码时的想法时,我将不得不花很长时间去看,太短或太聪明往往弊大于利。代码应可读。简洁是件好事,但不是那么简洁,以致下一个程序员无法理解。
The solution provided by Alex Varga “a in (b+c, b-c, c-b)” is compact and mathematically beautiful, but I wouldn’t actually write code that way because the next developer coming along would not immediately understand the purpose of the code.
Mark Ransom’s solution of
any((a + b == c, a + c == b, b + c == a))
is more clear but not much more succinct than
a + b == c or a + c == b or b + c == a
When writing code that someone else will have to look at, or that I will have to look at a long time later when I have forgotten what I was thinking when I wrote it, being too short or clever tends to do more harm than good. Code should be readable. So succinct is good, but not so succinct that the next programmer can’t understand it.
回答 11
请求的是更紧凑或更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))))
Request is for more compact OR more pythonic – I tried my hand at more compact.
given
import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
return x + y == z
This is 2 characters less than the original
any(g(*args) for args in f((a,b,c)))
test with:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
additionally, given:
h = functools.partial(itertools.starmap, g)
This is equivalent
any(h(f((a,b,c))))
回答 12
我想介绍一下我认为是最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之禅》
美丽胜于丑陋。
显式胜于隐式。
简单胜于复杂。
复杂胜于复杂。
扁平比嵌套更好。
稀疏胜于密集。
可读性很重要。
特殊情况还不足以打破规则。
尽管实用性胜过纯度。
错误绝不能默默传递。
除非明确地保持沉默。
面对模棱两可的想法,拒绝猜测的诱惑。
应该有一种-最好只有一种-显而易见的方法。
尽管除非您是荷兰人,否则一开始这种方式可能并不明显。
现在总比没有好。
虽然从来没有比这更好正确的现在。
如果实现难以解释,那是个坏主意。
如果实现易于解释,则可能是个好主意。
命名空间是一个很棒的主意-让我们做更多这些吧!
I want to present what I see as the most pythonic answer:
def one_number_is_the_sum_of_the_others(a, b, c):
return any((a == b + c, b == a + c, c == a + b))
The general case, non-optimized:
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
In terms of the Zen of Python I think the emphasized statements are more followed than from other answer:
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one– and preferably only one –obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea — let’s do more of those!
回答 13
作为我编程的一个老习惯,我认为将复杂的表达式放在子句中可以使其更具可读性,如下所示:
a == b+c or b == a+c or c == a+b
加号()
:
((a == b+c) or (b == a+c) or (c == a+b))
而且我认为使用多行也可以使更多的感觉像这样:
((a == b+c) or
(b == a+c) or
(c == a+b))
As an old habit of my programming, I think placing complex expression at right in a clause can make it more readable like this:
a == b+c or b == a+c or c == a+b
Plus ()
:
((a == b+c) or (b == a+c) or (c == a+b))
And also I think using multi-lines can also make more senses like this:
((a == b+c) or
(b == a+c) or
(c == a+b))
回答 14
以一般方式
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 ();
如果要使用位hack进行利用,则可以使用“!”,“ >> 1”和“ << 1”
我避免了除法,尽管它可以避免两次乘法以避免舍入错误。但是,检查溢出
In a generic way,
m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
if, manipulating an input variable is OK for you,
c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();
if you want to exploit using bit hacks, you can use “!”, “>> 1” and “<< 1”
I avoided division though it enables use to avoid two multiplications to avoid round off errors. However, check for overflows
回答 15
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
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