((x == a and y == b) 또는 (x == b and y == a))를 표현하는 더 우아한 방법이 있습니까?


108

((x == a and y == b) or (x == b and y == a))파이썬 으로 평가하려고 하는데 조금 장황한 것 같습니다. 더 우아한 방법이 있습니까?


8
객체의 유형에 따라 달라집니다 x,y, a,b있습니다 : 자들은의 int / 수레 / 문자열, 임의의 객체, 또는 무엇? 그들이 종류의 내장했고 경우는 모두를 유지할 수 있었다 x,ya,b정렬 된 순서로, 당신은 두 번째 지점을 피할 수 있습니다. 집합을 만들면 네 ​​가지 요소 각각 x,y, a,b이 해시되어 개체 유형에 따라 사소하거나 성능에 영향을 줄 수 있습니다.
smci

18
함께 일하는 사람들과 개발중인 프로젝트의 종류를 명심하십시오. 여기저기서 작은 파이썬을 사용합니다. 누군가가 여기에 답변 중 하나를 코딩했다면, 나는 무슨 일이 일어나고 있는지 Google에 완전히 문의해야합니다. 당신의 조건은 무엇이든 거의 읽을 수 있습니다.
Areks

3
나는 대체품을 귀찮게하지 않을 것입니다. 그들은 더 간결하지만 명확하지는 않지만 (IMHO) 나는 느려질 것이라고 생각합니다.
Barmar

22
이것은 전형적인 XYAB 문제입니다.
Tashus

5
그리고 일반적으로 순서 독립적 인 객체 컬렉션을 다루는 경우 sets / dicts / etc를 사용하십시오. 이것은 실제로 XY 문제입니다. 더 큰 코드베이스가 필요합니다. 나는 ((x == a and y == b) or (x == b and y == a))유키처럼 보일 수도 있지만 1) 그 의도는 명확하지 않고 비 Python 프로그래머가 아닌 사람들에게는 이해할 수 없으며 암호가 아닙니다 .2) 통역사 / 컴파일러는 항상 잘 처리하며 본질적으로 비 성능 코드를 생성 할 수는 없습니다. 대안. 따라서 '보다 우아'하면 심각한 단점이있을 수 있습니다.
smci

답변:


151

요소가 해시 가능하면 세트를 사용할 수 있습니다.

{a, b} == {y, x}

18
@Graham 아니요 오른쪽 세트에 정확히 두 개의 항목이 있기 때문에 그렇지 않습니다. 둘 다 a 인 경우 b가없고 둘 다 b 인 경우 a가 없으며 두 경우 모두 세트가 같을 수 없습니다.
홉스

12
반면 에 양쪽에 세 개의 요소가 있고 일대일로 일치시킬 수 있는지 테스트해야한다면 세트가 작동하지 않습니다. {1, 1, 2} == {1, 2, 2}. 이 시점에서 sorted또는 이 필요합니다 Counter.
user2357112는

11
읽기가 까다 롭습니다 ( "{}"을 "()"로 읽지 마십시오). 충분히 언급하면 ​​목적이 사라집니다.
Édouard

9
나는 그것이 파이썬이라는 것을 알고 있지만 값을 비교하기 위해 두 개의 새로운 세트를 만드는 것은 나에게 과도한 것처럼 보입니다 ... 그것을하는 함수를 정의하고 필요할 때 호출하십시오.
marxin

5
@marxin A 함수는 2 개의 간단한 세트 구성보다 더 큰 오버 킬입니다. 그리고 4 개의 인수로 읽기 어렵습니다.
Gloweye

60

나는 당신이 얻을 수있는 최선의 방법은 튜플로 패키지하는 것입니다.

if (a, b) == (x, y) or (a, b) == (y, x)

또는 세트 조회에서 랩핑 할 수도 있습니다.

if (a, b) in {(x, y), (y, x)}

몇 가지 의견으로 언급되었으므로 타이밍을 조정했으며 조회가 실패하면 튜플과 세트가 동일한 방식으로 수행되는 것처럼 보입니다.

from timeit import timeit

x = 1
y = 2
a = 3
b = 4

>>> timeit(lambda: (a, b) in {(x, y), (y, x)}, number=int(5e7))
32.8357742

>>> timeit(lambda: (a, b) in ((x, y), (y, x)), number=int(5e7))
31.6169182

조회가 성공하면 실제로 튜플이 더 빠르지 만

x = 1
y = 2
a = 1
b = 2

>>> timeit(lambda: (a, b) in {(x, y), (y, x)}, number=int(5e7))
35.6219458

>>> timeit(lambda: (a, b) in ((x, y), (y, x)), number=int(5e7))
27.753138700000008

멤버십 조회를 수행하고 있기 때문에 세트를 사용하기로 선택했으며 개념적으로 세트는 튜플보다 해당 사용 사례에 더 적합합니다. 특정 사용 사례에서 두 구조간에 유의 한 차이를 측정 한 경우 더 빠른 구조로 진행하십시오. 나는 여기서 성능이 요소라고 생각하지 않습니다.


12
튜플 방법은 매우 깨끗해 보입니다. 세트 사용의 성능 영향에 대해 걱정하고 있습니다. 그래도 할 수 if (a, b) in ((x, y), (y, x))있습니까?
Brilliand

18
@Brilliand 퍼포먼스 영향이 걱정된다면 파이썬은 당신을위한 언어가 아닙니다. :-D
Sneftel

나는 첫 번째 방법 인 두 튜플 비교를 정말 좋아합니다. 구문 분석하기가 쉽고 (한 번에 하나의 절) 각 절은 매우 간단합니다. 그리고 무엇보다 상대적으로 효율적이어야합니다.
Matthieu M.

set@Brilliand의 튜플 솔루션에 대한 답변 에서 솔루션 을 선호 해야하는 이유가 있습니까?
user1717828

세트는 객체가 해시 가능해야하므로 튜플은 종속성이 적은 일반적인 솔루션입니다. 일반적으로 중요하지는 않지만 성능은 값 비싼 해싱 및 동등성 검사를 사용하여 큰 객체를 처리 할 때 매우 다르게 보일 수 있습니다.
Dukeling

31

튜플은 약간 더 읽기 쉽습니다.

(x, y) == (a, b) or (x, y) == (b, a)

이것은 힌트를줍니다 : 우리는 시퀀스 x, y가 시퀀스 와 같은지 검사 a, b하지만 순서 는 무시합니다. 그것은 단지 평등을 설정 한 것입니다!

{x, y} == {a, b}

,목록이 아닌 튜플을 만듭니다. 지금 (x, y)(a, b)같은 튜플이있다 x, ya, b.
kissgyorgy

나는 파이썬 list형식이 아니라 "순서대로 배열 된 요소"라는 의미에서 "목록"을 의미했다 . 실제로 혼란스러워 편집했습니다.
토마스

27

항목을 해시 할 수 없지만 주문 비교를 지원하는 경우 다음을 시도해 볼 수 있습니다.

sorted((x, y)) == sorted((a, b))

이것은 해시 가능한 항목에서도 작동하기 때문에 (오른쪽?)보다 세계적인 솔루션입니다.
Carl Witthoft

5
@CarlWitthoft : 아니요 complex. 예를 들어 해시 가능하지만 정렬 할 수없는 유형이 있습니다 .
dan04

26

내 생각에 가장 우아한 방법은

(x, y) in ((a, b), (b, a))

{a, b} == {y, x}변수를 해시 할 수 있는지 생각할 필요가 없으므로 다른 답변에 표시된 것처럼 집합을 사용하는 것보다 낫습니다.


이것이 이전의 답변 과 어떻게 다릅니 까?
scohe001

5
@ scohe001 이전 답변에서 집합을 사용하는 튜플을 사용합니다. 그 이전 답변은이 솔루션을 고려했지만 권장 사항으로 나열하지 않았습니다.
Brilliand

25

이것들이 숫자라면을 사용할 수 있습니다 (x+y)==(a+b) and (x*y)==(a*b).

이것들이 비슷한 아이템이라면을 사용할 수 있습니다 min(x,y)==min(a,b) and max(x,y)==max(a,b).

그러나 ((x == a and y == b) or (x == b and y == a))명확하고 안전하며 더 일반적입니다.


2
하하 대칭 다항식 ftw!
Carsten S

2
이것이 오버플로 오류의 위험을 초래한다고 생각합니다.
Razvan Socol

3
정답, 특히 마지막 문장입니다. 간단하게 유지하십시오. 여러 개의 새 iterable 또는 이와 유사한 것을 요구하지 않아야합니다. 세트를 사용하려는 사람들 은 세트 객체의 구현을 살펴보고 이것을 꽉 조이는 루프에서 실행하려고한다고 상상해보십시오.
Z4-tier

3
@RazvanSocol OP는 데이터 유형이 무엇인지 말하지 않았 으며이 답변은 유형에 따른 솔루션의 자격을 부여합니다.
Z4-tier

21

둘 이상의 변수에 대한 일반화로 사용할 수 있습니다 itertools.permutations. 그 대신에

(x == a and y == b and z == c) or (x == a and y == c and z == b) or ...

우리는 쓸 수있다

(x, y, z) in itertools.permutations([a, b, c])

그리고 물론 두 가지 변수 버전 :

(x, y) in itertools.permutations([a, b])

5
좋은 대답입니다. 한 번에 하나의 순열 만 만들어지고 "in"검사가 중지되고 즉시 True를 반환하므로 메모리 생성 효율이 매우 뛰어나다는 점을 명심해야합니다 (이전에는 제너레이터를 많이 사용하지 않은 사람들의 경우). 일치하는 것이 발견되었습니다.
robertlayton

2
이 방법의 복잡성은 다음과 같습니다 O(N*N!). 11 개 변수의 경우 완료하는 데 1 초 이상 걸릴 수 있습니다. (나는 더 빠른 방법을 게시했지만 여전히 O(N^2)10k 변수에서 1 초 이상 걸리기 시작합니다. 그래서 이것은 빠르거나 일반적으로 수행 될 수있는 것 같습니다 (해시 가능성 / 순서 가능성), 그러나 둘다는 아닙니다 : P)
Aleksi Torhamo

15

튜플을 사용하여 데이터를 나타내고 다음과 같이 세트 포함을 확인할 수 있습니다.

def test_fun(x, y):
    test_set = {(a, b), (b, a)}

    return (x, y) in test_set

3
하나의 라이너로 작성되고 목록 (해시 불가 항목)을 작성하면 이것이 최선의 대답이라고 생각합니다. (나는 완전한 파이썬 초보자이지만).
Édouard

1
@ Édouard 이제 본질적으로 또 다른 대답이 있습니다 (어쨌든 더 효율적인 목록 대신 튜플로).
화려한

10

당신은 이미 가장 읽기 쉬운 해결책을 얻었습니다 . 더 적은 문자로 표현할 수있는 다른 방법이 있지만 읽기가 쉽지 않습니다.

값이 실제로 무엇을 나타내는 지에 따라 말하는 이름으로 함수에 수표래핑하는 것이 좋습니다 . 대안으로 또는 추가로, x, y 및 a, b 객체를 각각 전용 상위 클래스 객체로 모델링 한 다음 클래스 동등성 검사 방법 또는 전용 사용자 정의 함수에서 비교 논리와 비교할 수 있습니다.


3

OP는 두 변수의 경우에만 관련이있는 것처럼 보이지만 나중에 StackOverflow는 동일한 질문을 검색하는 사람들을위한 것이므로 일반적인 경우를 자세하게 다루려고 노력할 것입니다. 하나의 이전 답변에는 이미을 사용하는 일반 답변이 포함되어 itertools.permutations()있지만 각 항목마다 순열 O(N*N!)이 있기 N!때문에이 방법을 사용 하면 비교가 이루어 집니다 N. (이 답변의 주요 동기였습니다)

먼저 이전 답변의 일부 방법이 여기에 제시된 방법의 동기로 일반적인 경우에 어떻게 적용되는지 요약 해 보겠습니다. 임의의 (그러나 동일한) 길이의 튜플이 될 수있는를 참조 하고 A참조하는 데 사용 합니다 .(x, y)B(a, b)

set(A) == set(B)값은 빠르지 만 값을 해시 가능하고 튜플 중 하나에 중복 값이 ​​포함되어 있지 않은 경우에만 작동합니다. (예 : {1, 1, 2} == {1, 2, 2}@Daniel Mesejo의 답변에서 @ user2357112가 지적한대로)

이전 방법 대신 집합으로, 카운트와 함께 사전을 사용하여 중복 값으로 작업을 확장 할 수 있습니다 (이 여전히 모든 값, 해쉬 될 예를 들면 있도록하기 위해 필요로하는 제한이 변경 가능한 값을 좋아한다. list작동하지 않습니다)

def counts(items):
    d = {}
    for item in items:
        d[item] = d.get(item, 0) + 1
    return d

counts(A) == counts(B)

sorted(A) == sorted(B)해시 가능한 값은 필요하지 않지만 약간 느리며 대신 주문 가능한 값이 필요합니다. (그래서 complex작동하지 않습니다)

A in itertools.permutations(B)해시 가능 또는 주문 가능 값이 필요하지 않지만 이미 언급했듯이 O(N*N!)복잡성이 있으므로 11 개 항목 만 있어도 완료하는 데 1 초 이상 걸릴 수 있습니다.

그래서 일반적인 방법이 있지만 상당히 빠릅니까? 예, 왜 수동으로 각 항목의 양이 같은지 확인함으로써 : (이 항목의 복잡성은 O(N^2)큰 입력에도 좋지 않습니다. 내 컴퓨터에서 10k 항목은 1 초 이상 걸릴 수 있습니다. 10 개 항목과 같은 작은 입력은 다른 항목만큼 빠릅니다.)

def unordered_eq(A, B):
    for a in A:
        if A.count(a) != B.count(a):
            return False
    return True

최상의 성능을 얻으려면 dict먼저 기반 기반 방법 을 시도하고 , sorted해시 불가능한 값으로 인해 실패하면 기반 기반 방법으로 폴백하고, 정렬 불가능한 값으로 인해 실패하면 결국 count기반 기반 방법으로 폴백 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.