Answers:
为此,有一个有序的设置(可能的新链接)配方,可从Python 2文档中引用。无需修改即可在Py2.6或更高版本以及3.0或更高版本上运行。该接口几乎与普通集合完全相同,不同之处在于初始化应使用列表进行。
OrderedSet([1, 2, 3])
这是一个MutableSet,因此for的签名.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
。
union
在同一个类中同时调用两个方法。最后一个将“获胜”,第一个将在运行时不存在。这是因为OrderedSet.union
(无括号)必须引用单个对象。
字典的键是唯一的。因此,如果人们不理会有序字典中的值(例如,通过分配它们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 = __sub__
difference_update = __isub__
intersection = __and__
intersection_update = __iand__
issubset = __le__
issuperset = __ge__
symmetric_difference = __xor__
symmetric_difference_update = __ixor__
union = __or__
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
class方法fromkeys()
创建字典,然后简单地要求它keys()
。
>>> keywords = ['foo', 'bar', 'bar', 'foo', 'baz', 'foo']
>>> list(dict.fromkeys(keywords))
['foo', 'bar', 'baz']
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
不幸的是,在3.7+中,它不会保留顺序。
我可以做得比OrderedSet更好:bollton具有2/3兼容的纯Python 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
,但是这也意味着如果有任何问题,您可以给我个麻烦。:)
尽管其他人指出,Python中还没有内置的插入顺序保留集实现(但是),但我感到这个问题缺少一个答案,该答案指出了在PyPI上可以找到的内容。
有软件包:
其中一些实现是基于Raymond Hettinger提交给ActiveState的配方的,在其他答案中也提到了该配方。
my_set[5]
)remove(item)
这两个实现都为add(item)
和__contains__(item)
(item in my_set
)具有O(1 )。
OrderedSet
现在支持remove
如果您使用排序集来维护排序顺序,请考虑使用PyPI中的排序集实现。该sortedcontainers模块提供了一个SortedSet的只是这个目的。一些好处:纯Python,快速C实现,100%单元测试覆盖率,数小时的压力测试。
通过pip从PyPI安装很容易:
pip install sortedcontainers
请注意,如果不能pip install
,则只需从开源存储库中下拉sortedlist.py和sortedset.py文件。
安装完成后,您可以:
from sortedcontainers import SortedSet
help(SortedSet)
sortedcontainers模块还与几种替代实现保持性能比较。
对于询问Python的bag数据类型的评论,还有一种SortedList数据类型,可用于有效地实现bag。
SortedSet
类要求成员是可比较的并且是可哈希的。
set
和frozenset
还要求元素是可哈希的。可比较的约束是的加法SortedSet
,但也是显而易见的约束。
如果您已经在代码中使用了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)
,负号执行标准减法
太迟了一点,但我已经写了一类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/en/latest/
PyPI:https://pypi.python.org/pypi/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']
}
所述ParallelRegression包提供了SETLIST()有序集类,它是多个方法完成比基于ActiveState的配方的选项。它支持可用于列表的所有方法以及大多数(如果不是全部)可用于集合的方法。
正如其他答案所提到的,对于python 3.7+,该字典按定义排序。除了子类化之外,OrderedDict
我们还可以子类化abc.collections.MutableSet
或typing.MutableSet
使用dict的键存储值。
class OrderedSet(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] = None
def 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]
我将此代码放在一个小的库中,所以任何人都可以pip install
。
对于许多目的,只需调用sorted就足够了。例如
>>> 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]
如果要重复使用此功能,则调用sorted函数会产生开销,因此,只要您完成更改集合的操作,就可能希望保存结果列表。如果您需要维护唯一元素并进行排序,那么我建议您使用具有任意值(例如无)的集合中的OrderedDict。
因此,我还有一个小清单,很明显可以引入非唯一值。
我搜索了某种唯一列表的存在,但是后来意识到在添加元素之前测试元素的存在就可以了。
if(not new_element in my_list):
my_list.append(new_element)
我不知道这种简单方法是否有警告,但可以解决我的问题。