programing

컴팩트한 쓰기 방식 (a + b == c 또는 a + c == b 또는 b + c == a)

megabox 2023. 10. 26. 20:55
반응형

컴팩트한 쓰기 방식 (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)

하지만 그건 좀 이상합니다.

우리가 파이썬의 선을 본다면, 나의 강조점은:

팀 피터스 지음, 파이썬의 선

아름다운 것이 추한 것보다 낫습니다.
명시적인 것이 암묵적인 것보다 낫습니다.
간단한 것이 복잡한 것보다 낫습니다.
복잡한 것보다는 복잡한 것이 낫습니다.
평평한 것이 중첩된 것보다 낫습니다.
조밀한 것보다는 희소한 것이 낫습니다.
가독성이 중요합니다.
특별한 경우는 규칙을 어길 만큼 특별하지 않습니다.
비록 실용성이 순수함을 능가하지만요.
오류는 절대로 조용히 지나가서는 안됩니다.
명시적으로 침묵하지 않는 한.
애매모호한 상황에서 추측하고 싶은 유혹을 거절합니다.
그것을 할 수 있는 확실한 방법이 하나 있어야 합니다. 그리고 가급적이면 단 하나의 방법이 있어야 합니다.
비록 네덜란드인이 아니라면 처음에는 그 방법이 명백하지 않을 수도 있습니다.
지금이 안 하는 것보다 낫습니다.
비록 결코 지금보다 나아지지는 않지만 말입니다.
시행이 설명하기 어렵다면 좋지 않은 생각입니다.
구현이 설명하기 쉽다면 좋은 생각일 수도 있습니다.
이름공간은 아주 훌륭한 아이디어입니다. 더 많은 것을 해봅시다!

가장 명확하고 단순하며 설명하기 쉬운 것은 가장 피톤적인 해결책입니다.

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

더 좋은 것은, 이 코드를 이해하기 위해 파이썬을 알지 않아도 된다는 것입니다!그렇게 쉬워요.이것이 최선의 해결책입니다.다른 건 지적 자위권입니다.

또한 이 솔루션은 모든 제안 중 유일하게 단락이 발생하기 때문에 최고의 성능을 발휘하는 솔루션일 가능성이 높습니다. 만약a + b == c, 한 번의 덧셈과 비교만 수행됩니다.

a에 대한 세 가지 동등성 해결:

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

말씀드린 것처럼, 이것은 오직 양수에서만 작동합니다. 하지만 양수가 될 것이라는 것을 안다면, 이것은 함수가 아닌 직접 코드에서조차 매우 읽기 쉬운 해결책입니다.

약간의 반복 계산을 수행할 수도 있지만 성능을 목표로 지정하지는 않았습니다.

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

그것은 이미 매우 피톤적입니다.

더 많은 변수를 사용할 계획이라면 다음과 같은 방법으로 추론할 수 있습니다.

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개의 방정식을 쓰지 마십시오.

다음 코드를 사용하여 각 원소를 다른 원소의 합과 반복적으로 비교할 수 있으며, 이 코드는 해당 원소를 제외한 전체 목록의 합에서 계산됩니다.

 l = [a,b,c]
 any(sum(l)-e == e for e in l)

단순화하려고 하지 마세요.대신, 함수로 수행할 작업의 이름을 지정합니다.

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

이 상태를 "똑똑한" 것으로 대체하면 더 짧아질 수는 있지만, 더 가독성이 높아지지는 않습니다.그러나 이 상태를 그대로 두는 것은 매우 가독성이 떨어집니다. 이 세 가지 조건을 한 눈에 확인하는 이유를 알기가 어렵기 때문입니다.이것은 당신이 무엇을 확인하고 있는지 확실하게 알려줍니다.

성능과 관련하여 이러한 접근 방식은 함수 호출에 따른 오버헤드를 증가시키기는 하지만 반드시 해결해야 하는 병목 현상을 발견하지 않는 한 성능을 위해 가독성을 희생하지는 않습니다.그리고 항상 측정해야 합니다. 어떤 영리한 구현은 상황에 따라 기능 호출을 최적화하고 인라인화할 수 있기 때문입니다.

파이썬 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

그러나 일반적으로 변수가 3개 이상이 아닌 이상 원본이 더 읽기 쉽다는 것에 동의합니다.

(a+b-c)*(a+c-b)*(b+c-a) == 0

두 항의 합이 세 번째 항과 같으면 요인 중 하나가 0이 되어 전체 제품이 0이 됩니다.

그냥 다음은?

a == b + c or abs(a) == abs(b - c)

변수가 부호가 없는 경우에는 이 작업이 수행되지 않습니다.

(적어도 x86 플랫폼에서는) 코드 최적화의 관점에서 이것이 가장 효율적인 해결책인 것 같습니다.

현대의 컴파일러는 CDQ, XOR, SUB 명령어의 영리한 시퀀스를 사용함으로써 abs() 함수 호출 모두를 인라인화하고 부호 테스트와 그 이후의 조건부 분기를 피할 것입니다.따라서 위의 높은 수준의 코드는 낮은 지연 시간, 높은 처리량의 ALU 명령과 단 두 가지 조건만으로 표현됩니다.

Alex Varga가 제공한 솔루션 "ain (b+c, b-c, c-b)"은 컴팩트하고 수학적으로 아름답지만, 다음 개발자가 코드의 목적을 즉시 이해하지 못할 것이기 때문에 실제로 그렇게 코드를 작성하지는 않을 것입니다.

마크 랜섬의 해결책은

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

보다 더 명확하지만 훨씬 더 간결하지는 않습니다.

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

다른 사람이 보아야 할 코드를 작성할 때, 또는 작성할 때 생각했던 것을 잊어버린 후 한참 뒤에 보아야 할 코드를 작성할 때, 너무 짧거나 영리한 것은 득보다 실이 많은 경향이 있습니다.코드는 읽을 수 있어야 합니다.간단명료한 것은 좋지만, 다음 프로그래머가 이해할 수 없을 정도로 간결하지는 않습니다.

요청은 좀 더 콤팩트하거나 좀 더 파이톤적인 것입니다. 좀 더 콤팩트한 것을 시도해 보았습니다.

정해진

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

저는 제가 보기에 가장 피톤적인 대답을 제시하고자 합니다.

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 

파이썬의 선에 관해서는 다른 답변보다 강조된 진술이 더 뒤따른다고 생각합니다.

팀 피터스 지음, 파이썬의 선

아름다운 것이 추한 것보다 낫습니다.
명시적인 것이 암묵적인 것보다 낫습니다.
간단한 것이 복잡한 것보다 낫습니다.
복잡한 것보다는 복잡한 것이 낫습니다.
평평한 것이 중첩된 것보다 낫습니다.
조밀한 것보다는 희소한 것이 낫습니다.
가독성이 중요합니다.
특별한 경우는 규칙을 어길 만큼 특별하지 않습니다.
비록 실용성이 순수함을 능가하지만요.
오류는 절대로 조용히 지나가서는 안됩니다.
명시적으로 침묵하지 않는 한.
애매모호한 상황에서 추측하고 싶은 유혹을 거절합니다.
그것을 할 수 있는 확실한 방법이 하나 있어야 합니다. 그리고 가급적이면 단 하나의 방법이 있어야 합니다.
비록 네덜란드인이 아니라면 처음에는 그 방법이 명백하지 않을 수도 있습니다.
지금이 안 하는 것보다 낫습니다.
비록 결코 지금보다 나아지지는 않지만 말입니다.
시행이 설명하기 어렵다면 좋지 않은 생각입니다.
구현이 설명하기 쉽다면 좋은 생각일 수도 있습니다.
이름공간은 아주 훌륭한 아이디어입니다. 더 많은 것을 해봅시다!

제 프로그래밍의 오래된 습관처럼 복잡한 표현을 절에 올바르게 배치하면 다음과 같이 더 쉽게 읽을 수 있다고 생각합니다.

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

일반적으로 말하면,

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"을 사용할 수 있습니다.

나는 분할을 피했지만 두 번의 곱셈을 사용하여 반올림 오류를 방지할 수 있습니다.그러나 오버플로 여부를 확인합니다.

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

이렇게 작은 표현으로 얻을 수 있는 것은 거의 없지만, 합과 비교를 반복하지 않아도 되는 함수를 사용하는 것이 하나의 선택이 될 수 있습니다.작동 방식을 다음과 같이 변경하고자 할 때 좀 더 유지보수가 가능합니다.a + b == c * 2.

def equals_sum(a, b, c):
    return a + b == c

if (equals_sum(a, b, c)
or equals_sum(a, c, b)
or equals_sum(b, c, a)):
    ...

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

반응형