Существует несколько решений со встроенными функциями.
Отображение word_pair_list
на frozenset
:
word_pair_ctr = collections.Counter(map(frozenset, word_pair_list))
Результат:
Counter({frozenset({'apple', 'banana'}): 2, frozenset({'banana'}): 1})
Второй набор может выглядеть странно, но это только потому, что наборы содержаттолько один идентичный элемент.Извлечение все равно будет работать, т.е. word_pair_ctr[frozenset(["banana", "banana"])]
равно 1.
Вам необходимо использовать frozenset, а не обычный набор, потому что нормальные наборы не могут быть хешируемыми и поэтому не могут быть ключами в словаре (или счетчике).).
Сортировка пар перед вставкой в счетчик:
word_pair_ctr = collections.Counter(map(lambda x: tuple(sorted(x)), word_pair_list))
Результат выглядит следующим образом:
Counter({('apple', 'banana'): 2, ('banana', 'banana'): 1})
Хотя это может выглядеть лучше, вынеобходимо убедиться, что вы обращаетесь к счетам таким же образом, то есть word_pair_ctr[tuple(sorted([word1, word2]))]
, что может показаться даже более запутанным, чем предыдущее решение.
Счетчик подкласса
Третий вариант - сделатьВаш собственный класс счетчиков, который делает все это за вас.
class BiDirectionalCounter(collections.Counter):
def __init__(self, iterable):
super().__init__(map(lambda x: tuple(sorted(x)), iterable))
def __getitem__(self, items):
return super().__getitem__(tuple(sorted(items)))
Это, по-видимому, работает:
>>> BidirectionalCounter(word_pair_list)
BidirectionalCounter({('apple', 'banana'): 2, ('banana', 'banana'): 1})
Но чтобы по-настоящему работать, вам нужно реализовать все соответствующие dunder методы, т.е. __setitem__
, __add__
, __iadd__
, ...