Does Python have an ordered set?
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Darkness Approaches Looping
--
Chapters
00:00 Does Python Have An Ordered Set?
00:12 Answer 1 Score 396
00:49 Accepted Answer Score 253
01:25 Answer 3 Score 174
02:20 Answer 4 Score 60
03:28 Answer 5 Score 55
03:59 Thank you
--
Full question
https://stackoverflow.com/questions/1653...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #set
#avk47
ACCEPTED ANSWER
Score 255
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
ANSWER 2
Score 174
Update: This answer is obsolete as of Python 3.7. See jrc's answer above for a better solution. Will keep this answer here only for historical reasons.
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 = 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__)
ANSWER 3
Score 60
Implementations on PyPI
While others have pointed out that there is no built-in implementation of an insertion-order preserving set in Python (yet), I am feeling that this question is missing an answer which states what there is to be found on PyPI.
There are the packages:
- ordered-set (Python based)
 - collections-extended
 - boltons (under setutils.IndexedSet, Python-based)
 - oset (last updated in 2012)
 
Some of these implementations are based on the recipe posted by Raymond Hettinger to ActiveState which is also mentioned in other answers here.
Some differences
- ordered-set (version 1.1)
 - advantage: O(1) for lookups by index (e.g. 
my_set[5]) - oset (version 0.1.3)
 - advantage: O(1) for 
remove(item) - disadvantage: apparently O(n) for lookups by index
 
Both implementations have O(1) for add(item) and __contains__(item) (item in my_set).
ANSWER 4
Score 55
I can do you one better than an OrderedSet: boltons has a pure-Python IndexedSet type that is not only an ordered set, but also supports indexing (as with lists).
Simply pip install boltons (or copy setutils.py into your codebase), import the IndexedSet and:
>>> 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'
Everything is unique and retained in order. Full disclosure: I wrote the IndexedSet, but that also means you can bug me if there are any issues.