Key-ordered dict in Python

前端 未结 10 2206
北恋
北恋 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条回答
  •  Happy的楠姐
    2020-11-28 05:49

    here's a pastie: I Had a need for something similar. Note however that this specific implementation is immutable, there are no inserts, once the instance is created: The exact performance doesn't quite match what you're asking for, however. Lookup is O(log n) and full scan is O(n). This works using the bisect module upon a tuple of key/value (tuple) pairs. Even if you can't use this precisely, you might have some success adapting it to your needs.

    import bisect
    
    class dictuple(object):
        """
            >>> h0 = dictuple()
            >>> h1 = dictuple({"apples": 1, "bananas":2})
            >>> h2 = dictuple({"bananas": 3, "mangoes": 5})
            >>> h1+h2
            ('apples':1, 'bananas':3, 'mangoes':5)
            >>> h1 > h2
            False
            >>> h1 > 6
            False
            >>> 'apples' in h1
            True
            >>> 'apples' in h2
            False
            >>> d1 = {}
            >>> d1[h1] = "salad"
            >>> d1[h1]
            'salad'
            >>> d1[h2]
            Traceback (most recent call last):
            ...
            KeyError: ('bananas':3, 'mangoes':5)
       """
    
    
        def __new__(cls, *args, **kwargs):
            initial = {}
            args = [] if args is None else args
            for arg in args:
                initial.update(arg)
            initial.update(kwargs)
    
            instance = object.__new__(cls)
            instance.__items = tuple(sorted(initial.items(),key=lambda i:i[0]))
            return instance
    
        def __init__(self,*args, **kwargs):
            pass
    
        def __find(self,key):
            return bisect.bisect(self.__items, (key,))
    
    
        def __getitem__(self, key):
            ind = self.__find(key)
            if self.__items[ind][0] == key:
                return self.__items[ind][1]
            raise KeyError(key)
        def __repr__(self):
            return "({0})".format(", ".join(
                            "{0}:{1}".format(repr(item[0]),repr(item[1]))
                              for item in self.__items))
        def __contains__(self,key):
            ind = self.__find(key)
            return self.__items[ind][0] == key
        def __cmp__(self,other):
    
            return cmp(self.__class__.__name__, other.__class__.__name__
                      ) or cmp(self.__items, other.__items)
        def __eq__(self,other):
            return self.__items == other.__items
        def __format__(self,key):
            pass
        #def __ge__(self,key):
        #    pass
        #def __getattribute__(self,key):
        #    pass
        #def __gt__(self,key):
        #    pass
        __seed = hash("dictuple")
        def __hash__(self):
            return dictuple.__seed^hash(self.__items)
        def __iter__(self):
            return self.iterkeys()
        def __len__(self):
            return len(self.__items)
        #def __reduce__(self,key):
        #    pass
        #def __reduce_ex__(self,key):
        #    pass
        #def __sizeof__(self,key):
        #    pass
    
        @classmethod
        def fromkeys(cls,key,v=None):
            cls(dict.fromkeys(key,v))
    
        def get(self,key, default):
            ind = self.__find(key)
            return self.__items[ind][1] if self.__items[ind][0] == key else default
    
        def has_key(self,key):
            ind = self.__find(key)
            return self.__items[ind][0] == key
    
        def items(self):
            return list(self.iteritems())
    
        def iteritems(self):
            return iter(self.__items)
    
        def iterkeys(self):
            return (i[0] for i in self.__items)
    
        def itervalues(self):
            return (i[1] for i in self.__items)
    
        def keys(self):
            return list(self.iterkeys())
    
        def values(self):
            return list(self.itervalues())
        def __add__(self, other):
            _sum = dict(self.__items)
            _sum.update(other.__items)
            return self.__class__(_sum)
    
    if __name__ == "__main__":
        import doctest
        doctest.testmod()
    

提交回复
热议问题