как насчет обратного, мешок вещей? (неупорядоченный и неуникальный)
Вим
19
@wim collections.Counter- сумка Питона.
землетрясение
1
Что если что-то будет добавлено дважды? Какой должна быть позиция?
Маккей
2
@McKay - если бы он следовал поведению коллекций. OrdDict все равно находился бы в положении начального добавления
wojtow
Ответы:
206
Есть заказанный набор (возможна новая ссылка рецепт ), на который ссылается Документация Python 2 . Это работает на Py2.6 или позже и 3.0 или позже без каких-либо изменений. Интерфейс почти такой же, как обычный набор, за исключением того, что инициализация должна быть сделана со списком.
OrderedSet([1,2,3])
Это MutableSet, поэтому подпись для .unionне совпадает с сигнатурой набора, но поскольку она включает в себя __or__нечто подобное, можно легко добавить:
@staticmethoddef union(*sets):
union =OrderedSet()
union.union(*sets)return union
def union(self,*sets):for set in sets:
self |= set
Я почти уверен, что вам не разрешено использовать два метода unionв одном и том же классе. Последний «победит», а первый не сможет существовать во время выполнения. Это потому, что OrderedSet.union(без паренов) должен ссылаться на один объект.
Кевин
3
Существует также пакет "selectedset", основанный на том же рецепте, но реализованный на Cython - pypi.python.org/pypi/orderedset .
mbdevpl
149
Упорядоченный набор является функционально частным случаем упорядоченного словаря.
Ключи словаря являются уникальными. Таким образом, если игнорировать значения в упорядоченном словаре (например, назначая ихNone ), то он, по сути, имеет упорядоченный набор.
Начиная с Python 3.1 есть collections.OrderedDict. Ниже приведен пример реализации OrderedSet. (Обратите внимание, что только несколько методов должны быть определены или переопределены: collections.OrderedDictи collections.MutableSetвыполнять тяжелую работу.)
import collections
classOrderedSet(collections.OrderedDict, collections.MutableSet):def update(self,*args,**kwargs):if kwargs:raiseTypeError("update() takes no keyword arguments")for s in args:for e in s:
self.add(e)def add(self, elem):
self[elem]=Nonedef 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 = __sub__
difference_update = __isub__
intersection = __and__
intersection_update = __iand__
issubset = __le__
issuperset = __ge__
symmetric_difference = __xor__
symmetric_difference_update = __ixor__
union = __or__
@Casebash: да, один может понадобиться определить класс , OrderedSetкакие подклассы OrderedDictи abc.Setзатем определить __len__, __iter__и __contains__.
Stephan202
1
@ Stephan202: К сожалению, коллекции ABC живут collections, но в остальном хорошее предложение
u0b34a0f6ae
4
Это правда, но в результате у вас остается много потерянного пространства, что приводит к неоптимальной производительности.
Даниэль Катс
3
Дополнение; collection.OrderedDict также доступен в Python 2.7.
Нурблдофф
2
В результате OrderedSet([1,2,3])возникает ошибка TypeError. Как конструктор вообще работает? Отсутствующий пример использования.
xApple
90
Ответ - нет, но вы можете использовать collections.OrderedDictиз стандартной библиотеки Python только ключи (и значения как None) для той же цели.
Обновление : По состоянию на Python 3.7 (и CPython 3.6), стандарт dictбудет гарантированно сохранить порядок и более производительные , чем OrderedDict. (Однако для обратной совместимости и особенно читабельности вы можете продолжить использование OrderedDict.)
Вот пример того, как использовать dictв качестве упорядоченного набора, чтобы отфильтровать повторяющиеся элементы при сохранении порядка, тем самым эмулируя упорядоченный набор. Используйте dictметод класса, fromkeys()чтобы создать dict, затем просто попросите keys()обратную.
Возможно стоит упомянуть, что это также работает (быстрее) с ванилью dict.fromkeys(). Но в этом случае порядок ключей сохраняется только в реализациях CPython 3.6+, поэтому OrderedDictэто более переносимое решение, когда порядок имеет значение.
Jez
1
не будет работать, если значения не строковые
Anwar Hossain
4
@AnwarHossain keys = (1,2,3,1,2,1)list(OrderedDict.fromkeys(keys).keys())-> [1, 2, 3], python-3.7. Оно работает.
raratiru
1
Можем ли мы сделать вывод, что Set в Python 3.7+ также сохраняет порядок?
user474491
2
@ user474491 В отличие dict, setв Python 3.7+ , к сожалению , не сохраняет порядок.
CZ
39
Я могу сделать вас лучше, чем OrderedSet: boltons имеет чистый Python, 2/3-совместимый IndexedSetтип , который не только упорядоченное множество, но также поддерживает индексирование (как со списками).
Просто pip install boltons(или скопируйте setutils.pyв свою кодовую базу), импортируйте IndexedSetи:
>>>from boltons.setutils importIndexedSet>>> 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'
В то время как другие отмечают, что в Python нет встроенной реализации набора сохранения порядка вставки (пока), я чувствую, что в этом вопросе отсутствует ответ, в котором указано, что можно найти в PyPI .
Если вы используете упорядоченный набор для поддержания отсортированного порядка, рассмотрите возможность использования реализации отсортированного набора из PyPI. Модуль sortedcontainers предоставляет SortedSet именно для этой цели. Некоторые преимущества: чистый Python, реализация fast-as-C, 100% охват модульных тестов, часы стресс-тестирования.
Установка из PyPI легко с pip:
pip install sortedcontainers
Обратите внимание, что если вы не можете pip install, просто извлеките файлы sortedlist.py и sortedset.py из репозитория с открытым исходным кодом .
После установки вы можете просто:
from sortedcontainers importSortedSet
help(SortedSet)
Модуль sortedcontainers также поддерживает сравнение производительности с несколькими альтернативными реализациями.
Для комментария, который спрашивал о типе данных пакета Python, есть альтернативный тип данных SortedList, который можно использовать для эффективной реализации пакета.
Обратите внимание, что SortedSetкласс там требует, чтобы члены были сопоставимы и хэшируемы.
gsnedders
4
@gsnedders Встроенные, setа frozensetтакже требуют, чтобы элементы были хэшируемыми. Сопоставимое ограничение является дополнением для SortedSet, но это также очевидное ограничение.
получил
2
Как следует из названия, это не поддерживает порядок. Это ничего, кроме сортировки (set ([sequence])), что делает лучше?
2
@ldmtwo Я не уверен, на что вы ссылаетесь, но для ясности, SortedSet как часть Sorted Containers поддерживает отсортированный порядок.
GrantJ
2
@GrantJ - это разница между тем, поддерживает ли он порядок вставки или порядок сортировки . Большинство других ответов касаются порядка вставки. Я думаю, что вы уже знаете об этом, основываясь на первом предложении, но, вероятно, это то, что говорит ldmtwo.
Джастин
9
В случае, если вы уже используете панды в своем коде, его Indexобъект ведет себя почти как упорядоченный набор, как показано в этой статье .
Можете ли вы включить пример в этот ответ? Ссылки, как правило, ломаются через некоторое время.
Alechan
1
для разницы между наборами, которые вам действительно нужно использовать indA.difference(indB), знак минус выполняет стандартное вычитание
gg349
7
Немного опоздал к игре, но я написал класс, 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 fastTrue>>> sl.index('d')# so is finding the index of an element4>>> sl.insert(1,'d')# inserting an element already in raises a ValueErrorValueError>>> sl.index('d')4
Пакет ParallelRegression предоставляет класс упорядоченного набора setList (), который является более полным методом, чем параметры, основанные на рецепте ActiveState. Он поддерживает все методы, доступные для списков, и большинство, если не все методы, доступные для множеств.
Как отмечают другие ответы, как и для python 3.7+, dict упорядочен по определению. Вместо того, чтобы создавать подклассы, OrderedDictмы можем создавать подклассы abc.collections.MutableSetили typing.MutableSetиспользовать ключи dict для хранения наших значений.
classOrderedSet(typing.MutableSet[T]):"""A set that preserves insertion order by internally using a dict."""def __init__(self, iterable: t.Iterator[T]):
self._d = dict.fromkeys(iterable)def add(self, x: T)->None:
self._d[x]=Nonedef discard(self, x: T)->None:
self._d.pop(x)def __contains__(self, x: object)-> bool:return self._d.__contains__(x)def __len__(self)-> int:return self._d.__len__()def __iter__(self)-> t.Iterator[T]:return self._d.__iter__()
Тогда просто:
x =OrderedSet([1,2,-1,"bar"])
x.add(0)assert list(x)==[1,2,-1,"bar",0]
Для многих целей достаточно просто отсортированного вызова. Например
>>> 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.
Основная проблема этого подхода заключается в том, что добавление выполняется в O (n). Это означает, что с большими списками это становится медленнее. Встроенные в Python наборы очень хороши для ускорения добавления элементов. Но для простых случаев использования это, безусловно, работает!
collections.Counter
- сумка Питона.Ответы:
Есть заказанный набор (возможна новая ссылка рецепт ), на который ссылается Документация Python 2 . Это работает на Py2.6 или позже и 3.0 или позже без каких-либо изменений. Интерфейс почти такой же, как обычный набор, за исключением того, что инициализация должна быть сделана со списком.
Это MutableSet, поэтому подпись для
.union
не совпадает с сигнатурой набора, но поскольку она включает в себя__or__
нечто подобное, можно легко добавить:источник
update
,union
,intersection
.union
в одном и том же классе. Последний «победит», а первый не сможет существовать во время выполнения. Это потому, чтоOrderedSet.union
(без паренов) должен ссылаться на один объект.Упорядоченный набор является функционально частным случаем упорядоченного словаря.
Ключи словаря являются уникальными. Таким образом, если игнорировать значения в упорядоченном словаре (например, назначая их
None
), то он, по сути, имеет упорядоченный набор.Начиная с Python 3.1 есть
collections.OrderedDict
. Ниже приведен пример реализации OrderedSet. (Обратите внимание, что только несколько методов должны быть определены или переопределены:collections.OrderedDict
иcollections.MutableSet
выполнять тяжелую работу.)источник
OrderedSet
какие подклассыOrderedDict
иabc.Set
затем определить__len__
,__iter__
и__contains__
.collections
, но в остальном хорошее предложениеOrderedSet([1,2,3])
возникает ошибка TypeError. Как конструктор вообще работает? Отсутствующий пример использования.Ответ - нет, но вы можете использовать
collections.OrderedDict
из стандартной библиотеки Python только ключи (и значения какNone
) для той же цели.Обновление : По состоянию на Python 3.7 (и CPython 3.6), стандарт
dict
будет гарантированно сохранить порядок и более производительные , чемOrderedDict
. (Однако для обратной совместимости и особенно читабельности вы можете продолжить использованиеOrderedDict
.)Вот пример того, как использовать
dict
в качестве упорядоченного набора, чтобы отфильтровать повторяющиеся элементы при сохранении порядка, тем самым эмулируя упорядоченный набор. Используйтеdict
метод класса,fromkeys()
чтобы создать dict, затем просто попроситеkeys()
обратную.источник
dict.fromkeys()
. Но в этом случае порядок ключей сохраняется только в реализациях CPython 3.6+, поэтомуOrderedDict
это более переносимое решение, когда порядок имеет значение.keys = (1,2,3,1,2,1)
list(OrderedDict.fromkeys(keys).keys())
->[1, 2, 3]
, python-3.7. Оно работает.dict
,set
в Python 3.7+ , к сожалению , не сохраняет порядок.Я могу сделать вас лучше, чем OrderedSet: boltons имеет чистый Python, 2/3-совместимый
IndexedSet
тип , который не только упорядоченное множество, но также поддерживает индексирование (как со списками).Просто
pip install boltons
(или скопируйтеsetutils.py
в свою кодовую базу), импортируйтеIndexedSet
и:Все уникально и сохранено в порядке. Полное раскрытие: я написал
IndexedSet
, но это также означает, что вы можете меня беспокоить, если есть какие-либо проблемы . :)источник
Реализации на PyPI
В то время как другие отмечают, что в Python нет встроенной реализации набора сохранения порядка вставки (пока), я чувствую, что в этом вопросе отсутствует ответ, в котором указано, что можно найти в PyPI .
Есть пакеты:
Некоторые из этих реализаций основаны на рецепте, опубликованном Раймондом Хеттингером в ActiveState. который также упоминается в других ответах здесь.
Некоторые отличия
my_set[5]
)remove(item)
Обе реализации имеют O (1) для
add(item)
и__contains__(item)
(item in my_set
).источник
set.union
, не работают на нем, хотя он наследуетсяcollections.abc.Set
.OrderedSet
теперь поддерживаетremove
Если вы используете упорядоченный набор для поддержания отсортированного порядка, рассмотрите возможность использования реализации отсортированного набора из PyPI. Модуль sortedcontainers предоставляет SortedSet именно для этой цели. Некоторые преимущества: чистый Python, реализация fast-as-C, 100% охват модульных тестов, часы стресс-тестирования.
Установка из PyPI легко с pip:
Обратите внимание, что если вы не можете
pip install
, просто извлеките файлы sortedlist.py и sortedset.py из репозитория с открытым исходным кодом .После установки вы можете просто:
Модуль sortedcontainers также поддерживает сравнение производительности с несколькими альтернативными реализациями.
Для комментария, который спрашивал о типе данных пакета Python, есть альтернативный тип данных SortedList, который можно использовать для эффективной реализации пакета.
источник
SortedSet
класс там требует, чтобы члены были сопоставимы и хэшируемы.set
аfrozenset
также требуют, чтобы элементы были хэшируемыми. Сопоставимое ограничение является дополнением дляSortedSet
, но это также очевидное ограничение.В случае, если вы уже используете панды в своем коде, его
Index
объект ведет себя почти как упорядоченный набор, как показано в этой статье .Примеры из статьи:
источник
indA.difference(indB)
, знак минус выполняет стандартное вычитаниеНемного опоздал к игре, но я написал класс,
setlist
как частьcollections-extended
которого полностью реализуетSequence
иSet
GitHub: https://github.com/mlenzen/collections-extended
Документация: http://collections-extended.lenzm.net/en/latest/
PyPI: https://pypi.python.org/pypi/collections-extended
источник
Там нет
OrderedSet
в официальной библиотеке. Я делаю исчерпывающую таблицу всех структур данных для вашей справки.источник
Пакет ParallelRegression предоставляет класс упорядоченного набора setList (), который является более полным методом, чем параметры, основанные на рецепте ActiveState. Он поддерживает все методы, доступные для списков, и большинство, если не все методы, доступные для множеств.
источник
Как отмечают другие ответы, как и для python 3.7+, dict упорядочен по определению. Вместо того, чтобы создавать подклассы,
OrderedDict
мы можем создавать подклассыabc.collections.MutableSet
илиtyping.MutableSet
использовать ключи dict для хранения наших значений.Тогда просто:
Я поместил этот код в небольшую библиотеку , так что любой может
pip install
это сделать.источник
Для многих целей достаточно просто отсортированного вызова. Например
Если вы собираетесь использовать это несколько раз, при вызове отсортированной функции возникнут дополнительные издержки, так что вы можете захотеть сохранить результирующий список, если вы закончили изменять набор. Если вам нужно сохранить уникальные элементы и отсортированные, я согласен с предложением использовать OrderedDict из коллекций с произвольным значением, таким как None.
источник
Таким образом, у меня также был небольшой список, в котором у меня была возможность ввести неуникальные значения.
Я искал наличие какого-то уникального списка, но потом понял, что тестирование существования элемента перед его добавлением работает просто отлично.
Я не знаю, есть ли предостережения к этому простому подходу, но он решает мою проблему.
источник