Python有一个有序字典。那么有序集呢?


当前回答

在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

其他回答

在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

如果您已经在代码中使用了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

答案是否定的,但是您可以使用集合。OrderedDict来自Python标准库,其中只有键(值为None),用于相同的目的。

更新:从Python 3.7(和CPython 3.6)开始,标准dict保证保留顺序,并且比OrderedDict性能更好。(但是,为了向后兼容性,特别是可读性,您可能希望继续使用OrderedDict。)

下面是一个示例,说明如何使用dict作为有序集,在保留顺序的同时过滤掉重复项,从而模拟有序集。使用dict类方法fromkeys()创建一个dict,然后简单地要求返回keys()。

>>> keywords = ['foo', 'bar', 'bar', 'foo', 'baz', 'foo']

>>> list(dict.fromkeys(keywords))
['foo', 'bar', 'baz']

更新:这个答案在Python 3.7已经过时了。请参阅上面jrc的回答以获得更好的解决方案。出于历史原因,我将保留这个答案。


有序集在功能上是有序字典的一种特殊情况。

字典的键是唯一的。因此,如果忽略有序字典中的值(例如,将它们赋值为None),那么本质上是有序集。

从Python 3.1和2.7开始,就有了collections.OrderedDict。下面是OrderedSet的一个示例实现。(注意,只有少数方法需要定义或重写:集合。有序字典和集合。让我们来做繁重的工作。

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__)

PyPI上的实现

虽然其他人指出Python中还没有插入顺序保留集的内置实现,但我觉得这个问题缺少一个答案,它说明了在PyPI上可以找到什么。

这些是套餐:

有序集(基于Python) orderedset(基于Cython) collections-extended 波顿(在iterutils下。IndexedSet面向) Oset(最后更新于2012年)

其中一些实现是基于Raymond Hettinger发布到ActiveState的配方,在这里的其他回答中也提到了这个配方。

一些差异

有序集(版本1.1) 优点:O(1)用于索引查找(例如my_set[5]) Oset(版本0.1.3) 优点:O(1)用于移除(物品) 缺点:显然O(n)用于索引查找

这两个实现都有O(1)用于add(item)和__contains__(item) (my_set中的项目)。