diff -r ca2a35140e6a Doc/library/heapq.rst --- a/Doc/library/heapq.rst Mon Jan 09 06:17:39 2012 +0000 +++ b/Doc/library/heapq.rst Mon Jan 16 15:55:27 2012 +0100 @@ -81,15 +81,19 @@ The module also offers three general purpose functions based on heaps. -.. function:: merge(*iterables) +.. function:: merge(*iterables [, key]) Merge multiple sorted inputs into a single sorted output (for example, merge timestamped entries from multiple log files). Returns an :term:`iterator` over the sorted values. - Similar to ``sorted(itertools.chain(*iterables))`` but returns an iterable, does - not pull the data into memory all at once, and assumes that each of the input - streams is already sorted (smallest to largest). + *key* specifies a function of one argument that is used to extract a + comparison key from each list element: ``key=str.lower``. The default + value is ``None`` (compare the elements directly). + + Similar to ``sorted(itertools.chain(*iterables), key=key)`` but returns an + iterable, does not pull the data into memory all at once, and assumes that + each of the input streams is already sorted (smallest to largest). .. function:: nlargest(n, iterable, key=None) @@ -289,4 +293,3 @@ backwards, and this was also used to avoid the rewinding time. Believe me, real good tape sorts were quite spectacular to watch! From all times, sorting has always been a Great Art! :-) - diff -r ca2a35140e6a Lib/heapq.py --- a/Lib/heapq.py Mon Jan 09 06:17:39 2012 +0000 +++ b/Lib/heapq.py Mon Jan 16 15:55:27 2012 +0100 @@ -312,12 +312,17 @@ except ImportError: pass -def merge(*iterables): +def merge(*iterables, key=None): '''Merge multiple sorted inputs into a single sorted output. - Similar to sorted(itertools.chain(*iterables)) but returns a generator, - does not pull the data into memory all at once, and assumes that each of - the input streams is already sorted (smallest to largest). + Similar to sorted(itertools.chain(*iterables), key=key) but returns + a generator, does not pull the data into memory all at once, and + assumes that each of the input streams is already sorted (smallest to + largest). + + *key* specifies a function of one argument that is used to extract a + comparison key from each list element: ``key=str.lower``. The default + value is ``None`` (compare the elements directly). >>> list(merge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25])) [0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25] @@ -327,25 +332,51 @@ h = [] h_append = h.append - for itnum, it in enumerate(map(iter, iterables)): - try: - next = it.__next__ - h_append([next(), itnum, next]) - except _StopIteration: - pass - heapify(h) + if key is None: + for itnum, it in enumerate(map(iter, iterables)): + try: + next = it.__next__ + h_append([next(), itnum, next]) + except _StopIteration: + pass + heapify(h) - while 1: - try: - while 1: - v, itnum, next = s = h[0] # raises IndexError when h is empty - yield v - s[0] = next() # raises StopIteration when exhausted - _heapreplace(h, s) # restore heap condition - except _StopIteration: - _heappop(h) # remove empty iterator - except IndexError: - return + while 1: + try: + while 1: + # raises IndexError when h is empty + v, itnum, next = s = h[0] + yield v + s[0] = next() # raises StopIteration when exhausted + _heapreplace(h, s) # restore heap condition + except _StopIteration: + _heappop(h) # remove empty iterator + except IndexError: + return + else: + for itnum, it in enumerate(map(iter, iterables)): + try: + next = it.__next__ + v = next() + h_append([key(v), itnum, v, next]) + except _StopIteration: + pass + heapify(h) + + while 1: + try: + while 1: + # raises IndexError when h is empty + k, itnum, v, next = s = h[0] + yield v + v = next() # raises StopIteration when exhausted + s[0] = key(v) + s[2] = v + _heapreplace(h, s) # restore heap condition + except _StopIteration: + _heappop(h) # remove empty iterator + except IndexError: + return # Extend the implementations of nsmallest and nlargest to use a key= argument _nsmallest = nsmallest diff -r ca2a35140e6a Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py Mon Jan 09 06:17:39 2012 +0000 +++ b/Lib/test/test_heapq.py Mon Jan 16 15:55:27 2012 +0100 @@ -155,8 +155,15 @@ for i in range(random.randrange(5)): row = sorted(random.randrange(1000) for j in range(random.randrange(10))) inputs.append(row) - self.assertEqual(sorted(chain(*inputs)), list(self.module.merge(*inputs))) + self.assertEqual(sorted(chain(*inputs)), + list(self.module.merge(*inputs))) + key = lambda i: abs(i - 500) # something non-monotonous + for row in inputs: + row.sort(key=key) + self.assertEqual(sorted(chain(*inputs), key=key), + list(self.module.merge(*inputs, key=key))) self.assertEqual(list(self.module.merge()), []) + self.assertEqual(list(self.module.merge(key=key)), []) def test_merge_stability(self): class Int(int): diff -r ca2a35140e6a Misc/ACKS --- a/Misc/ACKS Mon Jan 09 06:17:39 2012 +0000 +++ b/Misc/ACKS Mon Jan 16 15:55:27 2012 +0100 @@ -871,6 +871,7 @@ Kevin Samborn Adrian Sampson Ilya Sandler +Simon Sapin Mark Sapiro Ty Sarna Ben Sayer