Is there a more elegant way to express ((x == a and y == b) or (x == b and y == a))?
I'm trying to evaluate ((x == a and y == b) or (x == b and y == a))
in Python, but it seems a bit verbose. Is there a more elegant way?
Solution 1:
If the elements are hashable, you could use sets:
{a, b} == {y, x}
Solution 2:
I think the best you could get is to package them into tuples:
if (a, b) == (x, y) or (a, b) == (y, x)
Or, maybe wrap that in a set lookup
if (a, b) in {(x, y), (y, x)}
Just since it was mentioned by a couple comments, I did some timings, and tuples and sets appear to perform identically here when the lookup fails:
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
Although tuples are actually faster when the lookup succeeds:
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
I chose to use a set because I'm doing a membership lookup, and conceptually a set is a better fit for that use-case than a tuple. If you measured a significant different between the two structures in a particular use case, go with the faster one. I don't think performance is a factor here though.
Solution 3:
Tuples make it slightly more readable:
(x, y) == (a, b) or (x, y) == (b, a)
This gives a clue: we're checking whether the sequence x, y
is equal to the sequence a, b
but ignoring ordering. That's just set equality!
{x, y} == {a, b}
Solution 4:
The most elegant way, in my opinion, would be
(x, y) in ((a, b), (b, a))
This is a better way than using sets, i.e. {a, b} == {y, x}
, as indicated in other answers because we don't need to think if the variables are hashable.
Solution 5:
If the items aren't hashable, but support ordering comparisons, you could try:
sorted((x, y)) == sorted((a, b))