Есть ли более элегантный способ выражения ((x == a и y == b) или (x == b и y == a))? [закрыто]

105
задан LetEpsilonBeLessThanZero 31 October 2019 в 17:18
поделиться

10 ответов

Если элементы hashable, Вы могли бы использовать наборы:

{a, b} == {y, x}
146
ответ дан 24 November 2019 в 03:54
поделиться

Кортежи делают это немного более читаемым:

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

Это дает ключ к разгадке: мы проверяем, равен ли список x, y списку a, b, но игнорирующий упорядочивание. Это только что установило равенство!

{x, y} == {a, b}
30
ответ дан 24 November 2019 в 03:54
поделиться

Если объекты не hashable, но сравнения упорядочивания поддержки, Вы могли бы попробовать:

sorted((x, y)) == sorted((a, b))
26
ответ дан 24 November 2019 в 03:54
поделиться

Я думаю лучшее, которое Вы могли получить, должен упаковать их в кортежи:

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

я принял решение использовать набор, потому что я делаю поиск членства, и концептуально набор является лучшим пригодным для того примера использования, чем кортеж. При измерении значительного другого между этими двумя структурами в конкретном варианте использования пойдите с более быстрым. Я не думаю, что производительность является фактором здесь все же.

57
ответ дан 24 November 2019 в 03:54
поделиться

Если это числа, можно использовать (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)) является ясным, безопасным, и более общим.

25
ответ дан 24 November 2019 в 03:54
поделиться

Самый изящный путь, по-моему, был бы

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

, Это - лучший путь, чем использование наборов, т.е. {a, b} == {y, x}, как обозначено в других ответах, потому что мы не должны думать, hashable ли переменные.

22
ответ дан 24 November 2019 в 03:54
поделиться

Можно использовать кортежи, чтобы представить данные и затем проверить на включение набора, как:

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

    return (x, y) in test_set
15
ответ дан 24 November 2019 в 03:54
поделиться

Как обобщение больше чем к двум переменным мы можем использовать 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])
20
ответ дан 24 November 2019 в 03:54
поделиться

Вы уже получили самое читаемое решение . Существуют другие способы выразить это, возможно, с меньшим количеством символов, но они менее просты для чтения.

В зависимости от то, что значения на самом деле представляют Ваш лучший выбор, к , переносят регистрацию функции с говорящим именем . Кроме того, или кроме того, можно смоделировать объекты x, y и a, b каждый в специализированном более высоком классе возражает, что затем можно соответствовать логике сравнения в методе проверки равенства класса или специализированной пользовательской функции.

9
ответ дан 24 November 2019 в 03:54
поделиться

Кажется, что OP только касался случая двух переменных, но так как StackOverflow также для тех, кто ищет тот же вопрос позже, я попытаюсь заняться универсальным случаем здесь в некоторых деталях; Один предыдущий ответ уже содержит универсальный ответ с помощью itertools.permutations(), но тот метод приводит к O(N*N!) сравнения, так как существует N! перестановки с N объекты каждый. (Это было основной мотивацией для этого ответа)

Первый, давайте подведем итог, как некоторые методы в предыдущих ответах относятся к универсальному случаю как мотивация для методики, представленной здесь. Я буду использовать A, чтобы послать к (x, y) и B относиться к (a, b), который может быть кортежами произвольных (но равный) длина.

set(A) == set(B) быстро, но только работает, если значения hashable, и можно гарантировать, что один из кортежей не содержит дублирующихся значений. (Например, {1, 1, 2} == {1, 2, 2}, как указано @user2357112 в соответствии с ответом @Daniel Mesejo)

предыдущий метод может быть расширен для работы с дублирующимися значениями при помощи словарей с количествами вместо наборов: (Это все еще имеет ограничение, что все значения должны быть hashable, таким образом, например, изменяемые значения как [1 112] не будет работать)

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), не требует hashable значений, но немного медленнее, и требует упорядочиваемых значений вместо этого. (Так, например, complex не будет работать)

A in itertools.permutations(B) уже, не требует hashable или упорядочиваемых значений, но как упомянутый, это имеет O(N*N!) сложность, поэтому даже со всего 11 объектами, это может принять секунду для окончания.

Так, там способ быть столь же общим, но сделать это значительно быстрее? Почему да, "вручную" проверяя, что существует то же количество каждого объекта: (Сложность этого O(N^2), таким образом, это не хорошо для больших исходных данных также; На моей машине, 10k объекты может принять секунду - но с меньшими исходными данными, как 10 объектов, это настолько же быстро как другие)

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

Для получения лучшей производительности, можно было бы хотеть попробовать dict - базирующийся метод сначала, отступить к sorted - базирующийся метод, если это перестало работать из-за unhashable значений и наконец отступает к count - базирующийся метод, если это также перестало работать из-за неупорядочиваемых значений.

3
ответ дан 24 November 2019 в 03:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: