{"id":2538,"date":"2023-04-12T16:04:49","date_gmt":"2023-04-12T21:04:49","guid":{"rendered":"http:\/\/www.ishygddt.xyz\/~blog\/?p=2538"},"modified":"2023-04-12T16:10:21","modified_gmt":"2023-04-12T21:10:21","slug":"python-heapq-merge-iterables","status":"publish","type":"post","link":"http:\/\/www.ishygddt.xyz\/~blog\/2023\/04\/python-heapq-merge-iterables","title":{"rendered":"Ordered merge of iterables in Python"},"content":{"rendered":"<p>Just found out about this cool feature in the Python standard library that allows you to merge two iterables based on a comparison:<\/p>\n<pre><code class=\"language-python\" data-line=\"\">from heapq import merge as merge_heapwise\n\nsome_numbers = (1, 5, 10, 15)\nother_numbers = (2, 4, 6, 8, 10, 12, 14, 16)\n\nmerged_numbers = tuple(merge_heapwise(some_numbers, other_numbers))  # Using a tuple so comparisons work, for didactic demo reasons\nassert merged_numbers == (1, 2, 4, 5, 6, 8, 10, 12, 14, 15, 16)<\/code><\/pre>\n<p>It's lazy, so you <em>can<\/em> use it for merging unbounded streams, though beware it could be considered \"slightly destructive\": it'll be internally \"hoarding\" 1 item from each iterable it didn't yield from that iteration (obviously, this is necessarily a part of the design, since it's got to have both items before it can compare them.) It supports an arbitrary number of input iterables.<\/p>\n<p>It supports parameter <code class=\"language-python\" data-line=\"\">key<\/code>, so you can specify some pre-comparison interpretation of the elements you're merging (such as <code class=\"language-python\" data-line=\"\">key=lambda e: float(e.get(&#039;x&#039;))<\/code>, which I just recently used to merge two streams of SVG element generators into a reasonable order for rendering.)<\/p>\n<p>It isn't really <em>fully general<\/em>; unless you wanted to make a wrapper class overriding the behavior of the comparison operators, you can't use an arbitrary function for deciding which element this function yields; however, for my use-case, it was pretty handy to have this function pre-written in the standard library.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just found out about this cool feature in the Python standard library that allows you to merge two iterables based on a comparison: from heapq import merge as merge_heapwise some_numbers = (1, 5, 10, 15) other_numbers = (2, 4, 6, 8, 10, 12, 14, 16) merged_numbers = tuple(merge_heapwise(some_numbers, other_numbers)) # Using a tuple so comparisons &hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-2538","post","type-post","status-publish","format-standard","hentry","category-drafts"],"_links":{"self":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts\/2538","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/comments?post=2538"}],"version-history":[{"count":5,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts\/2538\/revisions"}],"predecessor-version":[{"id":2543,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/posts\/2538\/revisions\/2543"}],"wp:attachment":[{"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/media?parent=2538"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/categories?post=2538"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.ishygddt.xyz\/~blog\/wp-json\/wp\/v2\/tags?post=2538"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}