Key-ordered dict in Python

前端 未结 10 2169
北恋
北恋 2020-11-28 05:14

I am looking for a solid implementation of an ordered associative array, that is, an ordered dictionary. I want the ordering in terms of keys, not of insertion order.

相关标签:
10条回答
  • 2020-11-28 05:39

    An ordered tree is usually better for this cases, but random access is going to be log(n). You should keep into account also insertion and removal costs...

    0 讨论(0)
  • 2020-11-28 05:39

    I'm not sure which python version are you working in, but in case you like to experiment, Python 3.1 includes and official implementation of Ordered dictionaries: http://www.python.org/dev/peps/pep-0372/ http://docs.python.org/3.1/whatsnew/3.1.html#pep-372-ordered-dictionaries

    0 讨论(0)
  • 2020-11-28 05:42

    The sortedcontainers module provides a SortedDict type that meets your requirements. It basically glues a SortedList and dict type together. The dict provides O(1) lookup and the SortedList provides O(N) iteration (it's extremely fast). The whole module is pure-Python and has benchmark graphs to backup the performance claims (fast-as-C implementations). SortedDict is also fully tested with 100% coverage and hours of stress. It's compatible with Python 2.6 through 3.4.

    0 讨论(0)
  • 2020-11-28 05:43

    Here's one option that has not been mentioned in other answers, I think:

    • Use a binary search tree (Treap/AVL/RB) to keep the mapping.
    • Also use a hashmap (aka dictionary) to keep the same mapping (again).

    This will provide O(n) ordered traversal (via the tree), O(1) random access (via the hashmap) and O(log n) insertion/deletion (because you need to update both the tree and the hash).

    The drawback is the need to keep all the data twice, however the alternatives which suggest keeping a list of keys alongside a hashmap are not much better in this sense.

    0 讨论(0)
  • 2020-11-28 05:44

    Here is my own implementation:

    import bisect
    class KeyOrderedDict(object):
       __slots__ = ['d', 'l']
       def __init__(self, *args, **kwargs):
          self.l = sorted(kwargs)
          self.d = kwargs
    
       def __setitem__(self, k, v):
          if not k in self.d:
             idx = bisect.bisect(self.l, k)
             self.l.insert(idx, k)
           self.d[k] = v
    
       def __getitem__(self, k):
          return self.d[k]
    
       def __delitem__(self, k):
          idx = bisect.bisect_left(self.l, k)
          del self.l[idx]
          del self.d[k]
    
       def __iter__(self):
          return iter(self.l)
    
       def __contains__(self, k):
          return k in self.d
    

    The use of bisect keeps self.l ordered, and insertion is O(n) (because of the insert, but not a killer in my case, because I append far more often than truly insert, so the usual case is amortized O(1)). Access is O(1), and iteration O(n). But maybe someone had invented (in C) something with a more clever structure ?

    0 讨论(0)
  • 2020-11-28 05:46

    The ordereddict package ( http://anthon.home.xs4all.nl/Python/ordereddict/ ) that I implemented back in 2007 includes sorteddict. sorteddict is a KSO ( Key Sorted Order) dictionary. It is implemented in C and very space efficient and several times faster than a pure Python implementation. Downside is that only works with CPython.

    >>> from _ordereddict import sorteddict
    >>> x = sorteddict()
    >>> x[1] = 1.0
    >>> x[3] = 3.3
    >>> x[2] = 2.2
    >>> print x
    sorteddict([(1, 1.0), (2, 2.2), (3, 3.3)])
    >>> for i in x:
    ...    print i, x[i]
    ... 
    1 1.0
    2 2.2
    3 3.3
    >>> 
    

    Sorry for the late reply, maybe this answer can help others find that library.

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