*** Lib/heapq.py.ORIG 2005-03-13 09:32:58.000000000 +0100 --- Lib/heapq.py 2005-03-14 14:07:51.000000000 +0100 *************** *** 307,312 **** --- 307,423 ---- except ImportError: pass + class Heap(object): + __slots__ = ('_heap', '_decorate_item', '_undecorate_item') + def __init__(self, iterable_or_sequence=(), copy=True, heapified=False, key=None, cmp=None, reverse=False): + iter(iterable_or_sequence) # raises TypeError + try: + len(iterable_or_sequence) + iterable_or_sequence[0] + except (TypeError, IndexError): + copy = True + + if key or cmp or reverse: + decorator = self._ItemDecorator(key, cmp, reverse) + decorate, undecorate = decorator.decorate, decorator.undecorate + self._heap = [ decorate(item) for item in iterable_or_sequence ] + else: + decorate = undecorate = self._identity + if copy: + self._heap = list(iterable_or_sequence) + else: + self._heap = iterable_or_sequence + + self._decorate_item, self._undecorate_item = decorate, undecorate + + if not heapified: + heapify(self._heap) + + def __len__(self): + return len(self._heap) + + def __getitem__(self, pos): + return self._undecorate_item( self._heap[pos] ) + + class _DestructiveHeapIterator(object): + def __init__(self, heap_list, undecorate): + self._heap, self._undecorate = heap_list, undecorate + def __iter__(self): + heap, undecorate = self._heap, self._undecorate + pop = heappop + while heap: + yield undecorate(pop(heap)) + + def __iter__(self): + return iter(self._DestructiveHeapIterator(self._heap, self._undecorate_item)) + + def iter_clone(self): + return iter(self._DestructiveHeapIterator(self._heap[:], self._undecorate_item)) + + def pop(self): + return self._undecorate_item( heappop(self._heap) ) + + def push(self, item): + heappush(self._heap, self._decorate_item(item)) + + def pushpop(self, item): + if not self._heap: + return item + decorated_item = self._decorate_item(item) + if decorated_item <= self._heap[0]: + return item + return self._undecorate_item( heapreplace(self._heap, decorated_item) ) + + @staticmethod + def _identity(item): + return item + + class _ItemDecorator(object): + __slots__ = ('reverse', 'cmp', 'key', 'count') + class _CmpLowerEqual(object): + __slots__ = ('item', 'cmp') + def __init__(self, item, cmp): self.cmp, self.item = cmp, item + def __le__(self, other): return self.cmp(self.item, other.item) <= 0 + class _ReversedCmpLowerEqual(object): + __slots__ = ('item', 'cmp') + def __init__(self, item, cmp): self.cmp, self.item = cmp, item + def __le__(self, other): return self.cmp(other.item, self.item) <= 0 + class _ReversedLowerEqual(object): + __slots__ = 'item' + def __init__(self, item): self.item = item + def __le__(self, other): return other.item <= self.item + def __init__(self, key, cmp, reverse): + self.key, self.cmp, self.reverse = key, cmp, reverse + self.count = 0 # arbitrary compare key + def decorate(self, item): + key, cmp, reverse = self.key, self.cmp, self.reverse + if key: + item_key = key(item) + else: + item_key = item + if reverse: + if cmp: + item_key = self._ReversedCmpLowerEqual(item_key, cmp) + else: + item_key = self._ReversedLowerEqual(item_key) + elif cmp: + item_key = self._CmpLowerEqual(item_key, cmp) + + if key: + if reverse: + self.count -= 1 + else: + self.count += 1 + return (item_key, self.count, item) + else: + return item_key + def undecorate(self, item): + if self.key: + return item[-1] + else: + return item.item + + if __name__ == "__main__": # Simple sanity test heap = [] *************** *** 317,319 **** --- 428,441 ---- while heap: sort.append(heappop(heap)) print sort + + # Simple sanity test for Heap class + def reverse_cmp(a,b): + if b <= a: return -1 + else: return 1 + heap = Heap(reverse=True, cmp=reverse_cmp, key=Heap._ItemDecorator._ReversedLowerEqual) + map(heap.push, data) + print heap[0] + print list(heap.iter_clone()) + print heap[0] + print list(heap)