def test_iterators(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) od = OrderedDict(pairs) self.assertEqual(list(od), [t[0] for t in pairs]) self.assertEqual(od.keys()[:], [t[0] for t in pairs]) self.assertEqual(od.values()[:], [t[1] for t in pairs]) self.assertEqual(od.items()[:], pairs) self.assertEqual(list(od.iterkeys()), [t[0] for t in pairs]) self.assertEqual(list(od.itervalues()), [t[1] for t in pairs]) self.assertEqual(list(od.iteritems()), pairs) self.assertEqual(list(reversed(od)), [t[0] for t in reversed(pairs)])
def test_iterators(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) od = OrderedDict(pairs) self.assertEqual(list(od), [t[0] for t in pairs]) self.assertEqual(od.keys()[:], [t[0] for t in pairs]) self.assertEqual(od.values()[:], [t[1] for t in pairs]) self.assertEqual(od.items()[:], pairs) self.assertEqual(list(od.iterkeys()), [t[0] for t in pairs]) self.assertEqual(list(od.itervalues()), [t[1] for t in pairs]) self.assertEqual(list(od.iteritems()), pairs) self.assertEqual(list(reversed(od)), [t[0] for t in reversed(pairs)])
class OrderedSet(collections.MutableSet, collections.Sequence): """ An OrderedSet is a custom MutableSet that remembers its order, so that every entry has an index that can be looked up. Based on version written by Luminoso Technologies: https://github.com/LuminosoInsight/ordered-set Unlike that implementation, this class uses OrderedDict as storage and supports key removal. We drop support for indexing, and add support for fixed-size sets with maxlen parameter. With a small modification, this class can be made into an LRU cache. """ def __init__(self, iterable=None, maxlen=None): self._mapping = OrderedDict() self._maxlen = maxlen if iterable is not None: self |= iterable def __len__(self): return len(self._mapping) def __getitem__(self, index): """ Get the item at a given index. If `index` is a slice, you will get back that slice of items. If it's the slice [:], exactly the same object is returned. (If you want an independent copy of an OrderedSet, use `OrderedSet.copy()`.) If `index` is an iterable, you'll get the OrderedSet of items corresponding to those indices. This is similar to NumPy's "fancy indexing". """ if index == SLICE_ALL: return self elif hasattr(index, '__index__') or isinstance(index, slice): result = self._mapping.keys()[index] if isinstance(result, list): return OrderedSet(result) else: return result elif isiterable(index): keys = self._mapping.keys() return OrderedSet([keys[i] for i in index]) else: raise TypeError("Don't know how to index an OrderedSet by %r" % index) def copy(self): return OrderedSet(self) def __getstate__(self): if len(self) == 0: # The state can't be an empty list. # We need to return a truthy value, or else __setstate__ won't be run. # # This could have been done more gracefully by always putting the state # in a tuple, but this way is backwards- and forwards- compatible with # previous versions of OrderedSet. return (None,) else: return list(self) def __setstate__(self, state): if state == (None,): self.__init__([]) else: self.__init__(state) def __contains__(self, key): return key in self._mapping def add(self, key): """ Add `key` as an item to this OrderedSet, then return its index. If `key` is already in the OrderedSet, return the index it already had. """ if key not in self._mapping: if self._maxlen is None or len(self._mapping) < self._maxlen: self._mapping[key] = 1 else: self._mapping.popitem(last=False) self._mapping[key] = 1 append = add def discard(self, key): del self._mapping[key] def __iter__(self): return self._mapping.iterkeys() def __reversed__(self): return reversed(self._mapping.keys()) def __repr__(self): if not self: return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, list(self)) def __eq__(self, other): if isinstance(other, OrderedSet): return len(self) == len(other) and \ self._mapping.keys() == other._mapping.keys() try: other_as_set = set(other) except TypeError: # If `other` can't be converted into a set, it's not equal. return False else: return set(self) == other_as_set
class OrderedSet(collections.MutableSet, collections.Sequence): """ An OrderedSet is a custom MutableSet that remembers its order, so that every entry has an index that can be looked up. Based on version written by Luminoso Technologies: https://github.com/LuminosoInsight/ordered-set Unlike that implementation, this class uses OrderedDict as storage and supports key removal. We drop support for indexing, and add support for fixed-size sets with maxlen parameter. With a small modification, this class can be made into an LRU cache. """ def __init__(self, iterable=None, maxlen=None): self._mapping = OrderedDict() self._maxlen = maxlen if iterable is not None: self |= iterable def __len__(self): return len(self._mapping) def __getitem__(self, index): """ Get the item at a given index. If `index` is a slice, you will get back that slice of items. If it's the slice [:], exactly the same object is returned. (If you want an independent copy of an OrderedSet, use `OrderedSet.copy()`.) If `index` is an iterable, you'll get the OrderedSet of items corresponding to those indices. This is similar to NumPy's "fancy indexing". """ if index == SLICE_ALL: return self elif hasattr(index, '__index__') or isinstance(index, slice): result = self._mapping.keys()[index] if isinstance(result, list): return OrderedSet(result) else: return result elif isiterable(index): keys = self._mapping.keys() return OrderedSet([keys[i] for i in index]) else: raise TypeError("Don't know how to index an OrderedSet by %r" % index) def copy(self): return OrderedSet(self) def __getstate__(self): if len(self) == 0: # The state can't be an empty list. # We need to return a truthy value, or else __setstate__ won't be run. # # This could have been done more gracefully by always putting the state # in a tuple, but this way is backwards- and forwards- compatible with # previous versions of OrderedSet. return (None, ) else: return list(self) def __setstate__(self, state): if state == (None, ): self.__init__([]) else: self.__init__(state) def __contains__(self, key): return key in self._mapping def add(self, key): """ Add `key` as an item to this OrderedSet, then return its index. If `key` is already in the OrderedSet, return the index it already had. """ if key not in self._mapping: if self._maxlen is None or len(self._mapping) < self._maxlen: self._mapping[key] = 1 else: self._mapping.popitem(last=False) self._mapping[key] = 1 append = add def discard(self, key): del self._mapping[key] def __iter__(self): return self._mapping.iterkeys() def __reversed__(self): return reversed(self._mapping.keys()) def __repr__(self): if not self: return '%s()' % (self.__class__.__name__, ) return '%s(%r)' % (self.__class__.__name__, list(self)) def __eq__(self, other): if isinstance(other, OrderedSet): return len(self) == len(other) and \ self._mapping.keys() == other._mapping.keys() try: other_as_set = set(other) except TypeError: # If `other` can't be converted into a set, it's not equal. return False else: return set(self) == other_as_set