128c128 < 'nlargest', 'nsmallest', 'heappushpop'] --- > 'nlargest', 'nsmallest', 'heappushpop', 'Heap'] 129a130 > from operator import itemgetter 130a132,139 > try: > from _thread import allocate_lock as Lock > except ImportError: > from _dummy_thread import allocate_lock as Lock > > ################################################################################ > ### MinHeap > ################################################################################ 182,230d190 < def _heappushpop_max(heap, item): < """Maxheap version of a heappush followed by a heappop.""" < if heap and item < heap[0]: < item, heap[0] = heap[0], item < _siftup_max(heap, 0) < return item < < def _heapify_max(x): < """Transform list into a maxheap, in-place, in O(len(x)) time.""" < n = len(x) < for i in reversed(range(n//2)): < _siftup_max(x, i) < < def nlargest(n, iterable): < """Find the n largest elements in a dataset. < < Equivalent to: sorted(iterable, reverse=True)[:n] < """ < if n < 0: < return [] < it = iter(iterable) < result = list(islice(it, n)) < if not result: < return result < heapify(result) < _heappushpop = heappushpop < for elem in it: < _heappushpop(result, elem) < result.sort(reverse=True) < return result < < def nsmallest(n, iterable): < """Find the n smallest elements in a dataset. < < Equivalent to: sorted(iterable)[:n] < """ < if n < 0: < return [] < it = iter(iterable) < result = list(islice(it, n)) < if not result: < return result < _heapify_max(result) < _heappushpop = _heappushpop_max < for elem in it: < _heappushpop(result, elem) < result.sort() < return result < 306a267,301 > ################################################################################ > ### MaxHeap > ################################################################################ > > def _heappop_max(heap): > """Maxheap version of heappop""" > lastelt = heap.pop() # raises appropriate IndexError if heap is empty > if heap: > returnitem = heap[0] > heap[0] = lastelt > _siftup_max(heap, 0) > else: > returnitem = lastelt > return returnitem > > def _heapreplace_max(heap, item): > """Maxheap version of heapreplace""" > returnitem = heap[0] # raises appropriate IndexError if heap is empty > heap[0] = item > _siftup_max(heap, 0) > return returnitem > > def _heappushpop_max(heap, item): > """Maxheap version of a heappush followed by a heappop.""" > if heap and item < heap[0]: > item, heap[0] = heap[0], item > _siftup_max(heap, 0) > return item > > def _heapify_max(x): > """Transform list into a maxheap, in-place, in O(len(x)) time.""" > n = len(x) > for i in reversed(range(n//2)): > _siftup_max(x, i) > 343c338,382 < # If available, use C implementation --- > ################################################################################ > ### Basic nlargest() and nsmallest() without a key-function > ################################################################################ > > def nlargest(n, iterable): > """Find the n largest elements in a dataset. > > Equivalent to: sorted(iterable, reverse=True)[:n] > """ > if n < 0: > return [] > it = iter(iterable) > result = list(islice(it, n)) > if not result: > return result > heapify(result) > _heappushpop = heappushpop > for elem in it: > _heappushpop(result, elem) > result.sort(reverse=True) > return result > > def nsmallest(n, iterable): > """Find the n smallest elements in a dataset. > > Equivalent to: sorted(iterable)[:n] > """ > if n < 0: > return [] > it = iter(iterable) > result = list(islice(it, n)) > if not result: > return result > _heapify_max(result) > _heappushpop = _heappushpop_max > for elem in it: > _heappushpop(result, elem) > result.sort() > return result > > > ################################################################################ > ### If available, use C implementation > ################################################################################ > 348a388,391 > ################################################################################ > ### merge() > ################################################################################ > 384c427,430 < # Extend the implementations of nsmallest and nlargest to use a key= argument --- > ################################################################################ > ### Add key-function to nlargest() and nsmallest() > ################################################################################ > 459a506,592 > ################################################################################ > ### Heap class > ################################################################################ > > class Heap: > '''Fully encapsulated heap class > > Features: > * Thread-safe update operations > * Comparison stability (equal keys returned in same order added) > * Key-functions (allowing the heap to work with non-comparable > objects such as functions) > * Minheap or maxheap > * Easily extendable using subclassing > ! Add __getinitargs__ for pickling or a __reduce__ method > > ''' > > def __init__(self, iterable=None, key=None, maxheap=False): > > # Save the public attributes > self.lock = Lock() > self.maxheap = maxheap > self.key = key > > # Build the internal decorate/undecorate functions > step = -1 if maxheap else 1 > counter = count(0, step).__next__ > if key is None: > self._wrap = lambda value: (value, counter()) > self._unwrap = itemgetter(0) > else: > self._wrap = lambda value: (key(value), counter(), value) > self._unwrap = itemgetter(2) > > # Populate the initial heap > if iterable is None: > self._data = [] > else: > print(iterable) > self._data = list(map(self._wrap, iterable)) > heaper = _heapify_max if maxheap else heapify > with self.lock: > heaper(self._data) > > def __len__(self): > 'Number of values in the heap' > return len(self._data) > > def __iter__(self): > 'Iterate over the heap values in heapified order (not sorted order)' > return map(self._unwrap, self._data) > > def push(self, value): > 'Add a value to the heap' > item = self._wrap(value) > pusher = _heappush_max if self.maxheap else heappush > with self.lock: > pusher(self._data, item) > > def pop(self): > 'Remove and return the min (or max) value from the heap' > popper = _heappop_max if self.maxheap else heappop > with self.lock: > result = popper(self._data) > return self._unwrap(result) > > def pushpop(self, value): > 'Same as a push() followed by a pop() but runs a little faster' > item = self._wrap(value) > pushpopper = _heappushpop_max if self.maxheap else heappushpop > with self.lock: > result = pushpopper(self._data, item) > return self._unwrap(result) > > def poppush(self, value): > 'Same as a pop() followed by a push() but runs a little faster' > item = self._wrap(value) > poppusher = _heapreplace_max if self.maxheap else heapreplace > with self.lock: > result = poppusher(self._data, item) > return self._unwrap(result) > > ################################################################################ > ### Command-line self-test > ################################################################################ >