development

간단한 작성 방법 (a + b == c 또는 a + c == b 또는 b + c == a)

big-blog 2020. 6. 24. 07:08
반응형

간단한 작성 방법 (a + b == c 또는 a + c == b 또는 b + c == a)


부울 식을 작성하는 더 간결하거나 비열한 방법이 있습니까?

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

나는 생각해 냈다

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

그러나 그것은 조금 이상합니다.


파이썬의 선을 보면 내 것을 강조합니다.

파이썬의 선 (The Zen of Python), Tim Peters

못생긴 것보다 아름답습니다.
암시적인 것보다 명시적인 것이 좋습니다.
단순함이 복잡한 것보다 낫습니다.
복잡한 것이 복잡한 것보다 낫습니다.
평평한 것이 중첩보다 낫습니다.
스파 스가 밀도보다 낫습니다.
가독성이 중요합니다.
특별한 경우는 규칙을 어길만큼 특별하지 않습니다.
실용성은 순도를 능가하지만.
오류가 자동으로 전달되지 않아야합니다.
명시 적으로 침묵하지 않는 한.
모호함에 직면하여 추측하려는 유혹을 거부하십시오.
그것을하는 명백한 방법이 있어야합니다.
네덜란드 인이 아니라면 처음에는 그 방법이 명확하지 않을 수 있습니다.
지금보다 결코 낫습니다.
결코 결코 올바른 것보다 낫지는 않지만지금.
구현이 설명하기 어렵다면 나쁜 생각입니다.
구현이 설명하기 쉬운 경우 좋은 생각 일 수 있습니다.
네임 스페이스는 훌륭한 아이디어 중 하나입니다. 더 많은 것을 해보자!

가장 Pythonic 솔루션은 가장 명확하고 간단하며 설명하기 쉬운 솔루션입니다.

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

더 좋은 점은이 코드를 이해하기 위해 Python을 알 필요조차 없습니다! 그것은이다 쉬운. 이것은 예약없이 최상의 솔루션입니다. 다른 것은 지적 자위 행위입니다.

더구나 이것은 제안 된 것 중 단 하나 뿐인 것이기 때문에 이것이 가장 성능이 좋은 솔루션 일 것입니다. 인 경우 a + b == c단일 추가 및 비교 만 수행됩니다.


에 대한 세 가지 평등을 해결 :

a in (b+c, b-c, c-b)

파이썬에는 시퀀스의 모든 요소를 ​​처리 하는 any함수가 or있습니다. 여기에서는 문장을 3 요소 튜플로 변환했습니다.

any((a + b == c, a + c == b, b + c == a))

참고 or개별 조건을 계산하는 것은 비싼 경우가 더 좋을 수도 원래의 구조를 유지하기 때문에, 단락이다.


당신이 양수만을 다루고 있다는 것을 안다면, 이것은 효과가 있으며 매우 깨끗합니다.

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()

그것은 꽤 파이썬 적이며, 아마도 가장 효율적인 방법 일 것입니다 (추가 함수 호출은 제외). 실제로 문제를 일으키지 않는 한 어쨌든 성능에 대해 너무 걱정하지 않아도됩니다.


세 개의 변수 만 사용하는 경우 초기 방법 :

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

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


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)

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.


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.


(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.


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.


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.


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))))

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!


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))

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


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

참고URL : https://stackoverflow.com/questions/32085675/compact-way-of-writing-a-b-c-or-a-c-b-or-b-c-a

반응형