Advertisement
Guest User

Untitled

a guest
Dec 12th, 2015
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.13 KB | None | 0 0
  1. from collections.abc import *
  2. from reprlib import recursive_repr as _recursive_repr
  3. from collections import OrderedDict
  4.  
  5. class _ListDictKeysView(KeysView):
  6.  
  7.     def __reversed__(self):
  8.         yield from reversed(self._mapping)
  9.  
  10. class _ListDictItemsView(ItemsView):
  11.  
  12.     def __reversed__(self):
  13.         for key in reversed(self._mapping):
  14.             yield (key, self._mapping[key])
  15.  
  16. class _ListDictValuesView(ValuesView):
  17.  
  18.     def __reversed__(self):
  19.         for key in reversed(self._mapping):
  20.             yield self._mapping[key]
  21.  
  22. _sentinel = object()
  23.  
  24.  
  25. class ListDict(dict):
  26.     'Dictionary that remembers insertion order'
  27.     # An inherited dict maps keys to values.
  28.     # The inherited dict provides __getitem__, __len__, __contains__, and get.
  29.     # The remaining methods are order-aware.
  30.     # Big-O running times for all methods are the same as regular dictionaries.
  31.  
  32.     def __init__(*args, **kwds):
  33.         '''Initialize an ordered dictionary.  The signature is the same as
  34.        regular dictionaries, but keyword arguments are not recommended because
  35.        their insertion order is arbitrary.
  36.  
  37.        '''
  38.         if not args:
  39.             raise TypeError("descriptor '__init__' of 'ListDict' object "
  40.                             "needs an argument")
  41.         self, *args = args
  42.         if len(args) > 1:
  43.             raise TypeError('expected at most 1 arguments, got %d' % len(args))
  44.         try:
  45.             # self.__root
  46.             self.__list
  47.         except AttributeError:
  48.             self.__map = {}
  49.             self.__list = []
  50.             self.__size = 0
  51.         self.__update(*args, **kwds)
  52.  
  53.     def __setitem__(self, key, value,
  54.                     dict_setitem=dict.__setitem__, len=len):
  55.         'od.__setitem__(i, y) <==> od[i]=y'
  56.         # If it's a new key, we need to track it.
  57.         if key not in self:
  58.             self.__map[key] = len(self.__list)
  59.             self.__list.append(key)
  60.             self.__size += 1
  61.            
  62.         dict_setitem(self, key, value)
  63.  
  64.     def __delitem__(self, key, dict_delitem=dict.__delitem__,
  65.                     sentinel=_sentinel):
  66.         'od.__delitem__(y) <==> del od[y]'
  67.         dict_delitem(self, key)
  68.        
  69.         # Remove the tracking for this item
  70.         index = self.__map.pop(key)
  71.         self.__list[index] = sentinel
  72.         self.__size -= 1
  73.        
  74.         self.__compact()
  75.  
  76.     def __iter__(self, sentinel=_sentinel):
  77.         'od.__iter__() <==> iter(od)'
  78.         for key in self.__list:
  79.             if key is not sentinel:
  80.                 yield key
  81.  
  82.     def __reversed__(self, sentinel=_sentinel, reversed=reversed):
  83.         'od.__reversed__() <==> reversed(od)'
  84.         for key in reversed(self.__list):
  85.             if key is not sentinel:
  86.                 yield key
  87.  
  88.     def clear(self):
  89.         'od.clear() -> None.  Remove all items from od.'
  90.         self.__list.clear()
  91.         self.__map.clear()
  92.         self.__size = 0
  93.         dict.clear(self) # dict.clear isn't cached?
  94.  
  95.     def popitem(self, last=True, sentinel=_sentinel,
  96.                 reversed=reversed, next=next):
  97.         '''od.popitem() -> (k, v), return and remove a (key, value) pair.
  98.        Pairs are returned in LIFO order if last is true or FIFO order if false.
  99.  
  100.        '''
  101.         if not self:
  102.             raise KeyError('dictionary is empty')
  103.        
  104.         if last:
  105.             lst = reversed(self.__list)
  106.         else:
  107.             lst = self.__list
  108.        
  109.         # Could use the key lookup to find this, but... meh.
  110.         # Note that attempting to compact first might have helped.
  111.         index, key = next((i, k)
  112.                 for i, k in enumerate(lst)
  113.                 if k is not sentinel)
  114.        
  115.         # We're calling dict.pop later, which won't handle
  116.         # the metadata.
  117.         del self.__map[key]
  118.         self.__list[index] = sentinel
  119.         self.__size -= 1
  120.        
  121.         self.__compact()
  122.        
  123.         value = dict.pop(self, key) # dict.pop isn't cached?
  124.         return key, value
  125.    
  126.     def __compact(self, sentinel=_sentinel,
  127.                   enumerate=enumerate, reversed=reversed):
  128.         ''' Compact the order __list if necessary.
  129.        '''
  130.         # May need to use this a lot in the upcoming `else`.
  131.         lst = self.__list
  132.         if not lst:
  133.             return
  134.        
  135.         if self.__size / len(lst) <= 0.5: #chosen at non-random
  136.             # Implementation 1: list comprehension
  137.             self.__list = [k for k in lst if k is not sentinel]
  138.            
  139.             # Implementation 2:
  140.             #    If only `list` had a `remove_all` method...
  141.             pass
  142.            
  143.             ''' Update all indices after a reordering.
  144.            
  145.            Should only be done when full (because it shouldn't be necessary otherwise).
  146.            '''
  147.             inner_map = self.__map
  148.             for index, key in enumerate(self.__list):
  149.                 inner_map[key] = index
  150.            
  151.         else:
  152.             # Even if the list isn't mostly empty,
  153.             # we can try to clear the back.
  154.             # TODO: How can this be more efficient?
  155.            
  156.             # Note: There exists a non-sentinel because
  157.             # otherwise, .__size/positive == 0 < positive.
  158.            
  159.             # # Implementation 1: Pop until it drops.
  160.             # while lst[-1] is sentinel:
  161.                 # lst.pop()
  162.            
  163.             # Implementation 2: Count the number of sentinels at the end.
  164.             emptys = next(i for i, k in enumerate(reversed(lst))
  165.                             if k is not sentinel)
  166.                      # guaranteed not to StopIteration since .__size > 0
  167.             del lst[:-emptys] #safe even if 0
  168.  
  169.     def move_to_end(self, key, last=True, sentinel=_sentinel,
  170.                     enumerate=enumerate, len=len):
  171.         '''Move an existing element to the end (or beginning if last==False).
  172.  
  173.        Raises KeyError if the element does not exist.
  174.        When last=True, acts like a fast version of self[key]=self.pop(key).
  175.        '''
  176.        
  177.         index = self.__map[key]
  178.         lst = self.__list
  179.         if last:
  180.             if index + 1 == len(lst):
  181.                 # already last
  182.                 # Not sure if this is the right path to optimize.
  183.                 # But I think redundant move_to_ends shouldn't
  184.                 # blow up the __list.
  185.                 return
  186.            
  187.             lst[index] = sentinel
  188.             if lst[-1] is sentinel:
  189.                 # can just swap with last
  190.                 lst[-1] = key
  191.                 self.__map[key] = len(lst) - 1
  192.             else:
  193.                 # append and maybe compact
  194.                 lst[index] = sentinel
  195.                 lst.append(key)
  196.                 self.__map[key] = len(lst) - 1
  197.                 self.__compact()
  198.         else:
  199.             # This is costly. But this shouldn't
  200.             # be a common case anyway, right?
  201.             # I mean, who repeatedly adds to the front
  202.             # of an OrderedDict?
  203.             # And this is basically the only costly
  204.             # operation I'm adding.
  205.            
  206.             lst[index] = sentinel
  207.            
  208.             # Propagate forward from the front.
  209.             for i, newkey in enumerate(lst):
  210.                 self.__map[key] = i
  211.                 lst[i], key = key, newkey
  212.                 if key is sentinel:
  213.                     break
  214.  
  215.     def __sizeof__(self):
  216.         sizeof = _sys.getsizeof
  217.         size = sizeof(self.__dict__)            # instance dictionary
  218.         size += sizeof(self.__map) * 2          # internal dict and inherited dict
  219.        
  220.         size += sizeof(self.__list)
  221.         size += sizeof(self.__size)
  222.         return size
  223.  
  224.     update = __update = MutableMapping.update
  225.  
  226.     def keys(self):
  227.         "D.keys() -> a set-like object providing a view on D's keys"
  228.         return _ListDictKeysView(self)
  229.  
  230.     def items(self):
  231.         "D.items() -> a set-like object providing a view on D's items"
  232.         return _ListDictItemsView(self)
  233.  
  234.     def values(self):
  235.         "D.values() -> an object providing a view on D's values"
  236.         return _ListDictValuesView(self)
  237.  
  238.     __ne__ = MutableMapping.__ne__
  239.  
  240.     __marker = object()
  241.  
  242.     def pop(self, key, default=__marker):
  243.         '''od.pop(k[,d]) -> v, remove specified key and return the corresponding
  244.        value.  If key is not found, d is returned if given, otherwise KeyError
  245.        is raised.
  246.  
  247.        '''
  248.         if key in self:
  249.             result = self[key]
  250.             del self[key]
  251.             return result
  252.         if default is self.__marker:
  253.             raise KeyError(key)
  254.         return default
  255.  
  256.     def setdefault(self, key, default=None):
  257.         'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
  258.         if key in self:
  259.             return self[key]
  260.         self[key] = default
  261.         return default
  262.  
  263.     @_recursive_repr()
  264.     def __repr__(self):
  265.         'od.__repr__() <==> repr(od)'
  266.         if not self:
  267.             return '%s()' % (self.__class__.__name__,)
  268.         return '%s(%r)' % (self.__class__.__name__, list(self.items()))
  269.  
  270.     def __reduce__(self):
  271.         'Return state information for pickling'
  272.         inst_dict = vars(self).copy()
  273.         for k in vars(ListDict()):
  274.             inst_dict.pop(k, None)
  275.         return self.__class__, (), inst_dict or None, None, iter(self.items())
  276.  
  277.     def copy(self):
  278.         'od.copy() -> a shallow copy of od'
  279.         return self.__class__(self)
  280.  
  281.     @classmethod
  282.     def fromkeys(cls, iterable, value=None):
  283.         '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
  284.        If not specified, the value defaults to None.
  285.  
  286.        '''
  287.         self = cls()
  288.         for key in iterable:
  289.             self[key] = value
  290.         return self
  291.  
  292.     def __eq__(self, other):
  293.         '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
  294.        while comparison to a regular mapping is order-insensitive.
  295.  
  296.        '''
  297.         if isinstance(other, ListDict):
  298.             return dict.__eq__(self, other) and all(map(_eq, self, other))
  299.         return dict.__eq__(self, other)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement