Does Python have an ordered set?

前端 未结 14 1260
予麋鹿
予麋鹿 2020-11-21 13:20

Python has an ordered dictionary. What about an ordered set?

相关标签:
14条回答
  • 2020-11-21 13:37

    For many purposes simply calling sorted will suffice. For example

    >>> 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]
    

    If you are going to use this repeatedly, there will be overhead incurred by calling the sorted function so you might want to save the resulting list, as long as you're done changing the set. If you need to maintain unique elements and sorted, I agree with the suggestion of using OrderedDict from collections with an arbitrary value such as None.

    0 讨论(0)
  • 2020-11-21 13:37

    So i also had a small list where i clearly had the possibility of introducing non-unique values.

    I searched for the existence of a unique list of some sort, but then realized that testing the existence of the element before adding it works just fine.

    if(not new_element in my_list):
        my_list.append(new_element)
    

    I don't know if there are caveats to this simple approach, but it solves my problem.

    0 讨论(0)
  • 2020-11-21 13:39

    An ordered set is functionally a special case of an ordered dictionary.

    The keys of a dictionary are unique. Thus, if one disregards the values in an ordered dictionary (e.g. by assigning them None), then one has essentially an ordered set.

    As of Python 3.1 and 2.7 there is collections.OrderedDict. The following is an example implementation of an OrderedSet. (Note that only few methods need to be defined or overridden: collections.OrderedDict and collections.MutableSet do the heavy lifting.)

    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__
    
    0 讨论(0)
  • 2020-11-21 13:39

    If you're using the ordered set to maintain a sorted order, consider using a sorted set implementation from PyPI. The sortedcontainers module provides a SortedSet for just this purpose. Some benefits: pure-Python, fast-as-C implementations, 100% unit test coverage, hours of stress testing.

    Installing from PyPI is easy with pip:

    pip install sortedcontainers
    

    Note that if you can't pip install, simply pull down the sortedlist.py and sortedset.py files from the open-source repository.

    Once installed you can simply:

    from sortedcontainers import SortedSet
    help(SortedSet)
    

    The sortedcontainers module also maintains a performance comparison with several alternative implementations.

    For the comment that asked about Python's bag data type, there's alternatively a SortedList data type which can be used to efficiently implement a bag.

    0 讨论(0)
  • There is an ordered set (possible new link) recipe for this which is referred to from the Python 2 Documentation. This runs on Py2.6 or later and 3.0 or later without any modifications. The interface is almost exactly the same as a normal set, except that initialisation should be done with a list.

    OrderedSet([1, 2, 3])
    

    This is a MutableSet, so the signature for .union doesn't match that of set, but since it includes __or__ something similar can easily be added:

    @staticmethod
    def union(*sets):
        union = OrderedSet()
        union.union(*sets)
        return union
    
    def union(self, *sets):
        for set in sets:
            self |= set
    
    0 讨论(0)
  • 2020-11-21 13:42

    As others have said, OrderedDict is a superset of an ordered set in terms of functionality, but if you need a set for interacting with an API and don't need it to be mutable, OrderedDict.keys() is actually an implementation 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)   
    

    The caveats are immutability and having to build up the set like a dict, but it's simple and only uses built-ins.

    0 讨论(0)
提交回复
热议问题