Хранить уникальные пары
Хочу хранить массив из уникальных элементов, то есть например есть массив [[1,2],[2,3]]
. Добавляю элемент [2,1]
. Итоговый массив остаётся прежним, т.к. [1,2]
и [2,1]
одинаковые
Хочу хранить массив из уникальных элементов, то есть например есть массив [[1,2],[2,3]]
. Добавляю элемент [2,1]
. Итоговый массив остаётся прежним, т.к. [1,2]
и [2,1]
одинаковые
Для хранения неповторяющихся данных берем обычное множество (например, set
в Python или HashSet
в Java). Для хранения пар создаем свой класс, и переопределяем для него равенство и получение хэша так, чтобы объекты и с одинаковым и с разным порядком элементов считались одинаковыми (для Python - методы __hash__
и __eq__
, для Java - .hashCode()
и .equals()
, в других языках что-то похожее тоже должно быть).
Реализация на Python:
class Pair:
def __init__(self, x, y):
self.x = x
self.y = y
def _comparing_key(self) -> tuple:
# Сравивать объекты будем по их элементам отсортированным по хэшу
if hash(self.x) < hash(self.y):
return (self.x, self.y)
else:
return (self.y, self.x)
def __hash__(self) -> int:
return hash(self._comparing_key())
def __eq__(self, other: object) -> bool:
if not isinstance(other, self.__class__):
return False
else:
return self._comparing_key() == other._comparing_key()
def __repr__(self):
return f"{self.__class__.__name__}({self.x!r}, {self.y!r})"
items = {Pair(1, 2), Pair(2, 3)}
print(items)
items.add(Pair(2, 1))
print(items)
Вывод:
{Pair(2, 3), Pair(1, 2)}
{Pair(2, 3), Pair(1, 2)}
$ python Python 3.10.0 (default, Oct 16 2021, 12:17:56) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. @>>> s = set() @>>> s.add(frozenset([1, 2])) @>>> s.add(frozenset([2, 3])) @>>> s {frozenset({2, 3}), frozenset({1, 2})} @>>> s.add(frozenset([2, 1])) @>>> s {frozenset({2, 3}), frozenset({1, 2})}
Если в списках могут быть одинаковые элементы, можно прибегнуть к конструкции frozenset(Counter(lst).items())
:
@>>> from collections import Counter @>>> s = set() @>>> s.add(frozenset(Counter([1, 2]).items())) @>>> s.add(frozenset(Counter([2, 3]).items())) @>>> s {frozenset({(1, 1), (2, 1)}), frozenset({(3, 1), (2, 1)})} @>>> s.add(frozenset(Counter([2, 1]).items())) @>>> s {frozenset({(1, 1), (2, 1)}), frozenset({(3, 1), (2, 1)})} @>>> s.add(frozenset(Counter([1, 1]).items())) @>>> s {frozenset({(1, 1), (2, 1)}), frozenset({(3, 1), (2, 1)}), frozenset({(1, 2)})}
Конструкция tuple(sorted(lst))
тоже решает задачу:
@>>> s = set() @>>> s.add(tuple(sorted([1, 2]))) @>>> s.add(tuple(sorted([2, 3]))) @>>> s {(2, 3), (1, 2)} @>>> s.add(tuple(sorted([2, 1]))) @>>> s {(2, 3), (1, 2)} @>>> s.add(tuple(sorted([1, 1]))) @>>> s {(2, 3), (1, 1), (1, 2)}