@@ -176,6 +176,16 @@ def heapify(x):
176176 for i in reversed (range (n // 2 )):
177177 _siftup (x , i )
178178
179+ def _heappop_max (heap ):
180+ """Maxheap version of a heappop."""
181+ lastelt = heap .pop () # raises appropriate IndexError if heap is empty
182+ if heap :
183+ returnitem = heap [0 ]
184+ heap [0 ] = lastelt
185+ _siftup_max (heap , 0 )
186+ return returnitem
187+ return lastelt
188+
179189def _heapreplace_max (heap , item ):
180190 """Maxheap version of a heappop followed by a heappush."""
181191 returnitem = heap [0 ] # raises appropriate IndexError if heap is empty
@@ -311,7 +321,7 @@ def _siftup_max(heap, pos):
311321except ImportError :
312322 pass
313323
314- def merge (* iterables ):
324+ def merge (* iterables , key = None , reverse = False ):
315325 '''Merge multiple sorted inputs into a single sorted output.
316326
317327 Similar to sorted(itertools.chain(*iterables)) but returns a generator,
@@ -321,31 +331,73 @@ def merge(*iterables):
321331 >>> list(merge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25]))
322332 [0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
323333
334+ If *key* is not None, applies a key function to each element to determine
335+ its sort order.
336+
337+ >>> list(merge(['dog', 'horse'], ['cat', 'fish', 'kangaroo'], key=len))
338+ ['dog', 'cat', 'fish', 'horse', 'kangaroo']
339+
324340 '''
325341
326342 h = []
327343 h_append = h .append
344+
345+ if reverse :
346+ _heapify = _heapify_max
347+ _heappop = _heappop_max
348+ _heapreplace = _heapreplace_max
349+ direction = - 1
350+ else :
351+ _heapify = heapify
352+ _heappop = heappop
353+ _heapreplace = heapreplace
354+ direction = 1
355+
356+ if key is None :
357+ for order , it in enumerate (map (iter , iterables )):
358+ try :
359+ next = it .__next__
360+ h_append ([next (), order * direction , next ])
361+ except StopIteration :
362+ pass
363+ _heapify (h )
364+ while len (h ) > 1 :
365+ try :
366+ while True :
367+ value , order , next = s = h [0 ]
368+ yield value
369+ s [0 ] = next () # raises StopIteration when exhausted
370+ _heapreplace (h , s ) # restore heap condition
371+ except StopIteration :
372+ _heappop (h ) # remove empty iterator
373+ if h :
374+ # fast case when only a single iterator remains
375+ value , order , next = h [0 ]
376+ yield value
377+ yield from next .__self__
378+ return
379+
328380 for order , it in enumerate (map (iter , iterables )):
329381 try :
330382 next = it .__next__
331- h_append ([next (), order , next ])
383+ value = next ()
384+ h_append ([key (value ), order * direction , value , next ])
332385 except StopIteration :
333386 pass
334- heapify (h )
335-
336- _heapreplace = heapreplace
387+ _heapify (h )
337388 while len (h ) > 1 :
338389 try :
339390 while True :
340- value , order , next = s = h [0 ]
391+ key_value , order , value , next = s = h [0 ]
341392 yield value
342- s [0 ] = next () # raises StopIteration when exhausted
343- _heapreplace (h , s ) # restore heap condition
393+ value = next ()
394+ s [0 ] = key (value )
395+ s [2 ] = value
396+ _heapreplace (h , s )
344397 except StopIteration :
345- heappop (h ) # remove empty iterator
398+ _heappop (h )
346399 if h :
347- # fast case when only a single iterator remains
348- value , order , next = h [0 ]
400+ key_value , order , value , next = h [0 ]
349401 yield value
350402 yield from next .__self__
351403
0 commit comments