I want to write a function that merges two sorted lists in Python 3.
For example:
>> merge_lists([2, 5, 9], [1, 6, 8, 10])
[1, 2, 5, 6, 8, 9, 10]
My implementation is as follows:
def merge_lists(L1, L2):
Outlist = []
while (L1 and L2):
if (L1[0] <= L2[0]):
item = L1.pop(0)
Outlist.append(item)
else:
item = L2.pop(0)
Outlist.append(item)
Outlist.extend(L1 if L1 else L2)
return Outlist
Can I make it better or more readable?
2 Answers 2
- Python's style guide says to use
lower_snake_casefor variable names. - You can use a turnery to assign the desired list to a variable to remove the duplicate code.
L1.pop(0)runs in \$O(n)\$ time, making your code \$O(n^2)\$. You can fix this by usingcollections.deque.
import collections
def merge_lists(list_1, list_2):
list_1 = collections.deque(list_1)
list_2 = collections.deque(list_2)
outlist = []
while (list_1 and list_2):
list_ = list_1 if list_1[0] <= list_2[0] else list_2
item = list_.popleft()
outlist.append(item)
outlist.extend(list_1 if list_1 else list_2)
return outlist
As highlighted in one of my previous questions, you can replace this with heapq.merge.
-
\$\begingroup\$ Did you mean ternary instead of turnery? \$\endgroup\$Roland Illig– Roland Illig2019年05月05日 04:08:35 +00:00Commented May 5, 2019 at 4:08
-
\$\begingroup\$ The whole point of hand-writing this algorithm was to be fast. Otherwise a simple
out = []; out.extend(a); out.extend(b); sort(out); return outwould have been enough. Converting the lists into deques copies all elements, doesn't it? \$\endgroup\$Roland Illig– Roland Illig2019年05月05日 04:24:50 +00:00Commented May 5, 2019 at 4:24 -
\$\begingroup\$ The funny thing is that that method will actually be almost as fast as a proper merge. Since python uses TimSort, it will take full advantage of the order already in the data. My guess is that sorting will be the 2nd fastest solution (2nd only to heapq.merge` \$\endgroup\$Oscar Smith– Oscar Smith2019年05月05日 07:10:34 +00:00Commented May 5, 2019 at 7:10
-
\$\begingroup\$ @RolandIllig reread point 2. Each loop you're copying each and every value in the loop anyway. You didn't tag this performance, but sorted and heapq are likely to be tons faster than anything you write. \$\endgroup\$2019年05月05日 10:08:37 +00:00Commented May 5, 2019 at 10:08
Since lists are passed by reference, the two lists that are passed as arguments will be half-empty after the function returns.
a = [1, 2, 4]
b = [3, 5]
merge_lists(a, b)
print(a) # is empty now but shouldn't
print(b) # only contains 5 now
Therefore you should not use list.pop at all but instead iterate over the lists via indexes, since these don't modify the lists.
Instead of the if-then-else expression at the end, you can just write:
Outlist.extend(L1)
Outlist.extend(L2)
You must log in to answer this question.
Explore related questions
See similar questions with these tags.