Python有一个有序字典。那么有序集呢?
当前回答
正如其他答案所提到的,对于python 3.7+,字典是按定义排序的。我们可以继承abc.collections.MutableSet或typing,而不是继承OrderedDict。MutableSet使用字典的键来存储我们的值。
import itertools
import 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]
我在一个小库中添加了这些代码和一些测试,所以任何人都可以安装它。
其他回答
正如其他人所说,OrderedDict在功能方面是有序集的超集,但如果你需要一个与API交互的集,并且不需要它是可变的,OrderedDict.keys()实际上是一个实现abc.collections.Set:
import random
from collections import OrderedDict, abc
a = list(range(0, 100))
random.shuffle(a)
# True
a == list(OrderedDict((i, 0) for i in a).keys())
# True
isinstance(OrderedDict().keys(), abc.Set)
注意事项是不可变性,必须像字典一样构建集合,但它很简单,只使用内置。
在Python 2文档中有一个有序集(可能是新的链接)配方。它运行在Py2.6或更高版本和3.0或更高版本上,无需任何修改。该接口几乎与普通的set完全相同,除了初始化应该使用一个列表。
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
有一个pip库是这样做的:
pip install ordered-set
然后你可以使用它:
from ordered_set import OrderedSet
如果您已经在代码中使用了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
我可以为您提供一个比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是我写的,但这也意味着如果有任何问题,您可以找我麻烦。:)
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录