Python имеет упорядоченный словарь. Как насчет упорядоченного набора?
У Python есть упорядоченный набор?
Ответ 1
Существует рецепт упорядоченного набора (возможный новый канал) для этого, который упоминается в документации Python 2. Это выполняется на Py2.6 или более поздней версии и версии 3.0 или более поздней версии без каких-либо изменений. Интерфейс почти точно совпадает с нормальным набором, за исключением того, что инициализация должна выполняться со списком.
OrderedSet([1, 2, 3])
Это MutableSet, поэтому подпись для .union
не совпадает с сигнатурой set, но поскольку она включает __or__
можно легко добавить что-то подобное:
@staticmethod
def union(*sets):
union = OrderedSet()
union.union(*sets)
return union
def union(self, *sets):
for set in sets:
self |= set
Ответ 2
Упорядоченный набор функционально является частным случаем упорядоченного словаря.
Клавиши словаря уникальны. Таким образом, если игнорировать значения в упорядоченном словаре (например, назначая их None
), то по существу есть упорядоченный набор.
Начиная с Python 3.1 collections.OrderedDict
, Ниже приведен пример реализации OrderedSet. (Обратите внимание, что нужно определить или переопределить только несколько методов: collections.OrderedDict
и collections.MutableSet
сделать тяжелый подъем.)
import collections
class OrderedSet(collections.OrderedDict, collections.MutableSet):
def update(self, *args, **kwargs):
if kwargs:
raise TypeError("update() takes no keyword arguments")
for s in args:
for e in s:
self.add(e)
def add(self, elem):
self[elem] = None
def discard(self, elem):
self.pop(elem, None)
def __le__(self, other):
return all(e in other for e in self)
def __lt__(self, other):
return self <= other and self != other
def __ge__(self, other):
return all(e in self for e in other)
def __gt__(self, other):
return self >= other and self != other
def __repr__(self):
return 'OrderedSet([%s])' % (', '.join(map(repr, self.keys())))
def __str__(self):
return '{%s}' % (', '.join(map(repr, self.keys())))
difference = property(lambda self: self.__sub__)
difference_update = property(lambda self: self.__isub__)
intersection = property(lambda self: self.__and__)
intersection_update = property(lambda self: self.__iand__)
issubset = property(lambda self: self.__le__)
issuperset = property(lambda self: self.__ge__)
symmetric_difference = property(lambda self: self.__xor__)
symmetric_difference_update = property(lambda self: self.__ixor__)
union = property(lambda self: self.__or__)
Ответ 3
Ответ отрицательный, но вы можете использовать collections.OrderedDict
из стандартной библиотеки Python только с ключами (и значениями, как None
) для той же цели.
Обновление: Начиная с Python 3.7 (и CPython 3.6), стандарт dict
гарантированно сохраняет порядок и более производительный, чем OrderedDict
. (Однако для обратной совместимости и особенно читабельности вы можете продолжить использовать OrderedDict
.)
Вот пример того, как использовать dict
в качестве упорядоченного набора для отфильтровывания дублирующихся элементов при сохранении порядка, тем самым эмулируя упорядоченный набор. Используйте метод класса dict
fromkeys()
, чтобы создать диктовку, а затем просто попросите вернуть keys()
.
>>> keywords = ['foo', 'bar', 'bar', 'foo', 'baz', 'foo']
>>> list(dict.fromkeys(keywords).keys())
['foo', 'bar', 'baz']
Ответ 4
Я могу сделать вас лучше, чем OrderedSet: у boltons есть чистый-Python, 2/3-совместимый тип IndexedSet
который является не только упорядоченным набором, но также поддерживает индексирование (как со списками).
Просто pip install boltons
(или скопируйте setutils.py
в свою кодовую базу), импортируйте IndexedSet
и:
>>> from boltons.setutils import IndexedSet
>>> x = IndexedSet(list(range(4)) + list(range(8)))
>>> x
IndexedSet([0, 1, 2, 3, 4, 5, 6, 7])
>>> x - set(range(2))
IndexedSet([2, 3, 4, 5, 6, 7])
>>> x[-1]
7
>>> fcr = IndexedSet('freecreditreport.com')
>>> ''.join(fcr[:fcr.index('.')])
'frecditpo'
Все уникально и сохраняется в порядке. Полное раскрытие: я написал IndexedSet
, но это также означает, что вы можете IndexedSet
ошибку, если есть какие-либо проблемы. :)
Ответ 5
Реализации на PyPI
В то время как другие указали, что в Python нет встроенной реализации набора для сохранения порядка вставки, я чувствую, что в этом вопросе отсутствует ответ, в котором говорится, что можно найти на PyPI.
Насколько мне известно, в настоящее время существует:
Обе версии основаны на рецепте Python по установке объектов для полного списка методов работы с множеством и их эквивалентов на основе операторов.
Сначала я отправился с упорядоченным набором, пока не использовал remove(item)
в первый раз, который разбил мой script на NotImplementedError
. Поскольку я до сих пор не использовал поиск по индексу, я тем временем переключился на oset.
Если вы знаете о других реализациях PyPI, дайте мне знать в комментариях.
Ответ 6
Если вы используете упорядоченный набор для поддержания упорядоченного порядка, рассмотрите возможность использования реализации отсортированного набора из PyPI. Модуль sortedcontainers предоставляет SortedSet только для этой цели. Некоторые преимущества: реализация pure-Python, fast-as-C, покрытие 100% unit test, часы стресс-тестирования.
Установка из PyPI проста с помощью pip:
pip install sortedcontainers
Обратите внимание, что если вы не можете pip install
, просто вытащите файлы sortedlist.py и sortedset.py из хранилища с открытым исходным кодом .
После установки вы можете просто:
from sortedcontainers import SortedSet
help(SortedSet)
Модуль sortedcontainers также поддерживает сравнение производительности с несколькими альтернативными реализациями.
Для комментария, который задал вопрос о типе данных пакета Python, в качестве альтернативы используется тип данных SortedList, который можно использовать для эффективного осуществления пакета.
Ответ 7
Если вы уже используете pandas в своем коде, его Index
объект ведет себя как упорядоченный набор, как показано в этой статье.
Ответ 8
Немного поздно к игре, но я написал класс setlist
как часть collections-extended
, который полностью реализует как Sequence
и Set
>>> from collections_extended import setlist
>>> sl = setlist('abracadabra')
>>> sl
setlist(('a', 'b', 'r', 'c', 'd'))
>>> sl[3]
'c'
>>> sl[-1]
'd'
>>> 'r' in sl # testing for inclusion is fast
True
>>> sl.index('d') # so is finding the index of an element
4
>>> sl.insert(1, 'd') # inserting an element already in raises a ValueError
ValueError
>>> sl.index('d')
4
GitHub: https://github.com/mlenzen/collections-extended
Документация: http://collections-extended.lenzm.net/ru/latest/
Ответ 9
Там нет OrderedSet
в официальной библиотеке. Я делаю исчерпывающий список всех структур данных для вашей справки.
DataStructure = {
'Collections': {
'Map': [
('dict', 'OrderDict', 'defaultdict'),
('chainmap', 'types.MappingProxyType')
],
'Set': [('set', 'frozenset'), {'multiset': 'collection.Counter'}]
},
'Sequence': {
'Basic': ['list', 'tuple', 'iterator']
},
'Algorithm': {
'Priority': ['heapq', 'queue.PriorityQueue'],
'Queue': ['queue.Queue', 'multiprocessing.Queue'],
'Stack': ['collection.deque', 'queue.LifeQueue']
},
'text_sequence': ['str', 'byte', 'bytearray']
}
Ответ 10
ParallelRegression пакет предоставляет setList() упорядоченный класс заданий, который больше по методу, чем параметры, основанные на рецепте ActiveState. Он поддерживает все доступные методы для списков и большинство, если не все методы, доступные для наборов.
Ответ 11
Для многих целей достаточно просто отсортировать сортировку. Например
>>> s = set([0, 1, 2, 99, 4, 40, 3, 20, 24, 100, 60])
>>> sorted(s)
[0, 1, 2, 3, 4, 20, 24, 40, 60, 99, 100]
Если вы собираетесь использовать это повторно, будут наноситься накладные расходы, вызвав сортированную функцию, чтобы вы могли сохранить полученный список, если вы закончили изменение набора. Если вам нужно поддерживать уникальные элементы и сортировать, я согласен с предложением использовать OrderedDict из коллекций с произвольным значением, например None.
Ответ 12
Поэтому у меня также был небольшой список, где я, очевидно, имел возможность вводить неединственные значения.
Я искал существование уникального списка какого-то рода, но потом понял, что тестирование существования элемента перед его добавлением отлично работает.
if(not new_element in my_list):
my_list.append(new_element)
Я не знаю, есть ли оговорки к этому простому подходу, но он решает мою проблему.
Ответ 13
Есть четыре типа заказов, которые могут потребоваться, я полагаю:
- Упорядочено по ключу
- Упорядочено по значению (я не слышал, чтобы кто-нибудь просил этого, хотя)
- Упорядочено по времени модификации
- Упорядочено по времени добавления
Я считаю, что collection.OrderedDict получает ваС# 4. Или вы можете удалить ключ и повторно добавить его для # 3.
Для # 1 вы, вероятно, должны проверить красно-черное дерево или treap:
- http://pypi.python.org/pypi/bintrees/0.3.0
- http://pypi.python.org/pypi/rbtree/
- http://stromberg.dnsalias.org/~dstromberg/treap/
Деревья Red-Black имеют низкую изменчивость во время работы (так что может быть лучше для интерактивных приложений), но не так быстро, как средняя средняя (что может быть лучше для пакетной обработки - treaps не реорганизуются сами, часто делая они быстро в среднем, но когда они реорганизуются, это может занять относительно долгое время).
Обе из них представляют собой структуры данных с реализациями на многих языках.
Ответ 14
Вы можете использовать reduce()
, чтобы получить список уникальных значений в одной строке:
>>> mylist = [4, 1, 2, 1, 3, 2, 4, 1, 3, 2, 3, 1, 3, 2, 4]
>>> reduce(lambda a, b: b[0] in a and a or a + b, [[i] for i in mylist])
[4, 1, 2, 3]
Ответ 15
>>> a = {3, 4, 2, 6, 1, 7}
>>> type(a)
<class 'set'>
>>> sorted(a, reverse=True)
[7, 6, 4, 3, 2, 1]
>>> sorted(a)
[1, 2, 3, 4, 6, 7]