Python有一个有序字典。那么有没有有序集合呢?
>>> keywords = ['foo', 'bar', 'bar', 'foo', 'baz', 'foo']
>>> list(dict.fromkeys(keywords))
['foo', 'bar', 'baz']
collections.OrderedDict
。dict.fromkeys()
也可以(更快地)实现相同的功能。但在这种情况下,只有在使用CPython 3.6+实现时才能保留键的顺序,因此在需要保持顺序时,使用OrderedDict
是一个更便携的解决方案。 - jezdict
不同,Python 3.7+ 中的 set
不幸地不保留顺序。 - c zdict
保留插入顺序,但在对其内容进行操作后不一定会保留顺序。 它还指出了OrderedDict
拥有但dict
没有的几个特性。 dict
可能足以解决这个问题,但不能因为dict
支持保留插入顺序就认为它完全替代了OrderedDict
。 - Mr. Lance E Sloan有一个有序集合(可能新链接)的方案可供使用,文档来源于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
update
、union
和intersection
。 - xAppleunion
的方法,最后一个会覆盖前面的方法并在运行时失效。这是因为 OrderedSet.union
(没有括号)必须引用单个对象。 - Kevin更新:截至Python 3.7,此回答已过时。请参见上面jrc的答案以获取更好的解决方案。只为历史原因保留此答案。
一个有序集合从功能上来说是有序字典的一种特殊情况。
字典的键是唯一的。因此,如果忽略有序字典中的值(例如将它们赋值为None
),那么基本上就得到了一个有序的集合。
自Python 3.1和2.7版本以来,有collections.OrderedDict
。以下是一个有序集合的示例实现。(注意,只需要定义或重写少量方法: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__)
OrderedSet([1,2,3])
会引发 TypeError 错误。构造函数是如何工作的?缺少使用示例。 - xAppledict
(因为它现在是有序的),并且使用collections.abc.MutableSet
。 - Asclepius虽然其他人指出Python中没有内置的保持插入顺序的集合实现(但是),我觉得这个问题缺少一个回答,说明可以在PyPI找到什么。
以下是一些包:
my_set[5]
)的时间复杂度为O(1)
- oset(版本0.1.3)
- 优点:remove(item)
的时间复杂度为O(1)
- 缺点:按索引查找的时间复杂度似乎为O(n)add(item)
和__contains__(item)
(item in my_set
)的时间复杂度为O(1)。collections.abc.Set
,但像set.union
这样的函数在其上不起作用。 - Tim DielsSortedSet
,它来自sortedcontainers 2.3.0,并带有许多其他有序的内容。 - ceprio>>> 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'
pip install sortedcontainers
from sortedcontainers import SortedSet
help(SortedSet)
sortedcontainers模块还与几种替代实现进行了性能比较。
对于询问Python的bag数据类型的评论,可以使用SortedList数据类型来高效地实现bag。
SortedSet
类要求成员是可比较和可哈希的。 - gsneddersset
和frozenset
也要求元素是可哈希的。SortedSet
增加了一个可比较性的限制,但这也是一个显而易见的约束。 - gotgenesimport typing
T = typing.TypeVar("T")
class OrderedSet(typing.MutableSet[T]):
"""A set that preserves insertion order by internally using a dict."""
def __init__(self, iterable: typing.Iterator[T]):
self._d = dict.fromkeys(iterable)
def add(self, x: T) -> None:
self._d[x] = None
def discard(self, x: T) -> None:
self._d.pop(x, None)
def __contains__(self, x: object) -> bool:
return self._d.__contains__(x)
def __len__(self) -> int:
return self._d.__len__()
def __iter__(self) -> typing.Iterator[T]:
return self._d.__iter__()
def __str__(self):
return f"{{{', '.join(str(i) for i in self)}}}"
def __repr__(self):
return f"<OrderedSet {self}>"
x = OrderedSet([1, 2, -1, "bar"])
x.add(0)
assert list(x) == [1, 2, -1, "bar", 0]
我在一个小库中添加了这段代码,并进行了一些测试, 这样任何人都可以直接pip install
它。
discard
方法永远不应该抛出KeyError
异常。此外,注意此代码没有提供合理的__repr__
方法。 - Jason Forbes如果您已经在代码中使用pandas,它的Index
对象就像有序集合一样工作,如此文所示。
以下是文章中的示例:
indA = pd.Index([1, 3, 5, 7, 9])
indB = pd.Index([2, 3, 5, 7, 11])
indA & indB # intersection
indA | indB # union
indA - indB # difference
indA ^ indB # symmetric difference
indA.difference(indB)
,减号执行标准减法。 - gg349pd.Index
允许存在重复元素,这一点与 Python 中的 set
不同。 - jfaccionisetlist
,作为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
官方库中没有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']
}
collections.Counter
是 Python 中的一个“袋子”。 - flornquakedict
现在是按插入顺序排序的(自Python 3.7起保证)。 - Walter Tross