snippetpythonMinor
Python - insertion sort
Viewed 0 times
insertionsortpython
Problem
Series post - I am reading through Introduction to Algorithms, 3rd Edition implementing each algorithm as I read them.
Pretty basic insertion sort. Only considering numbers initially - how could I make this better and/or have better tests?
Pretty basic insertion sort. Only considering numbers initially - how could I make this better and/or have better tests?
def insertion_sort(numbs):
for cur_index in range(1, len(numbs)):
cur_val = numbs[cur_index]
lookup_index = cur_index - 1
while lookup_index >= 0 and numbs[lookup_index] >= cur_val:
numbs[lookup_index + 1] = numbs[lookup_index]
lookup_index -= 1
numbs[lookup_index + 1] = cur_val
return numbs
def check_insertion_sort(input, expected):
result = insertion_sort(input)
if result != expected:
print "Result={} does not equal expected={} for input={}".format(result, expected, input)
else:
print "Success for input={}".format(input)
check_insertion_sort([5, 2, 4, 6, 1, 3], [1, 2, 3, 4, 5, 6])
check_insertion_sort([190, 2, 4, 6, 1, 3], [1, 2, 3, 4, 6, 190])
check_insertion_sort([-190, 2, 4, 6, 1, 3], [-190, 1, 2, 3, 4, 6])
check_insertion_sort([0, 0, 4, 6, 1, 3], [0, 0, 1, 3, 4, 6])
check_insertion_sort([0, 0], [0, 0])
check_insertion_sort([1, 0], [0, 1])Solution
First of all, awesome that you have written tests!
However, your checker is a bit verbose on the matching case. It is often considered good practice for automated tests to be as noise-free as possible. Consider the following outputs:
Ok, you have written just a few testcases, but I think you see my point: you'll miss the errors. Better would be just
Better: use a testing framework like unittest, py.test or doctest. Here's how it looks like doctest:
Now, this is a bit verbose, so my preference would probably to use py.test or nosetests, but the advantage of
Now, for another point. Your sorting is both in-place, and returns the list again.
For instance:
Suggestion: if you do in-place sort, make sure it is documented that the function modifies the input array. In general, I would prefer not returning the result, as to limit confusion.
I can't really see anything wrong with the implementation itself, but I'm not familiar enough with insertion sort.
Using
One thing I would really really like to advice is switching to Python 3 for learning. Python 2 is only supported up-to 2020, and a lot of people would be happy if more people learn Python 3 instead.
However, your checker is a bit verbose on the matching case. It is often considered good practice for automated tests to be as noise-free as possible. Consider the following outputs:
Success for input=...testcase...
... 300 lines of success ...
Success for input=...testcase...
Result=... does not equal expected=... for input=...
Success for input=...testcase...
... 300 lines of success ...
Success for input=...testcase...Ok, you have written just a few testcases, but I think you see my point: you'll miss the errors. Better would be just
Result=... does not equal expected=... for input=...
Failures: 1, Success: 601Better: use a testing framework like unittest, py.test or doctest. Here's how it looks like doctest:
def insertion_sort(numbs):
"""
>>> insertion_sort([5, 2, 4, 6, 1, 3])
[1, 2, 3, 4, 5, 6]
>>> insertion_sort([190, 2, 4, 6, 1, 3])
[1, 2, 3, 4, 6, 190]
>>> insertion_sort([-190, 2, 4, 6, 1, 3])
[-190, 1, 2, 3, 4, 6]
>>> insertion_sort([0, 0, 4, 6, 1, 3])
[0, 0, 1, 3, 4, 6]
>>> insertion_sort([0, 0])
[0, 0]
>>> insertion_sort([1, 0])
[0, 1]
"""
for cur_index in range(1, len(numbs)):
cur_val = numbs[cur_index]
lookup_index = cur_index - 1
while lookup_index >= 0 and numbs[lookup_index] >= cur_val:
numbs[lookup_index + 1] = numbs[lookup_index]
lookup_index -= 1
numbs[lookup_index + 1] = cur_val
return numbs
if __name__ == "__main__":
import doctest
doctest.testmod()Now, this is a bit verbose, so my preference would probably to use py.test or nosetests, but the advantage of
doctest is that it's built-in, and for simple tests it is sufficient.Now, for another point. Your sorting is both in-place, and returns the list again.
For instance:
>>> example = [6, 7, 1, 2]
>>> result = insertion_sort(example)
>>> result
[1, 2, 6, 7]
>>> example
[1, 2, 6, 7]Suggestion: if you do in-place sort, make sure it is documented that the function modifies the input array. In general, I would prefer not returning the result, as to limit confusion.
I can't really see anything wrong with the implementation itself, but I'm not familiar enough with insertion sort.
Using
range is fine for short lengths, but as this is a list-sort, you don't really know the values len(numbs) will take. Maybe use xrange instead? (Or better: upgrade to Python 3!).One thing I would really really like to advice is switching to Python 3 for learning. Python 2 is only supported up-to 2020, and a lot of people would be happy if more people learn Python 3 instead.
Code Snippets
Success for input=...testcase...
... 300 lines of success ...
Success for input=...testcase...
Result=... does not equal expected=... for input=...
Success for input=...testcase...
... 300 lines of success ...
Success for input=...testcase...Result=... does not equal expected=... for input=...
Failures: 1, Success: 601def insertion_sort(numbs):
"""
>>> insertion_sort([5, 2, 4, 6, 1, 3])
[1, 2, 3, 4, 5, 6]
>>> insertion_sort([190, 2, 4, 6, 1, 3])
[1, 2, 3, 4, 6, 190]
>>> insertion_sort([-190, 2, 4, 6, 1, 3])
[-190, 1, 2, 3, 4, 6]
>>> insertion_sort([0, 0, 4, 6, 1, 3])
[0, 0, 1, 3, 4, 6]
>>> insertion_sort([0, 0])
[0, 0]
>>> insertion_sort([1, 0])
[0, 1]
"""
for cur_index in range(1, len(numbs)):
cur_val = numbs[cur_index]
lookup_index = cur_index - 1
while lookup_index >= 0 and numbs[lookup_index] >= cur_val:
numbs[lookup_index + 1] = numbs[lookup_index]
lookup_index -= 1
numbs[lookup_index + 1] = cur_val
return numbs
if __name__ == "__main__":
import doctest
doctest.testmod()>>> example = [6, 7, 1, 2]
>>> result = insertion_sort(example)
>>> result
[1, 2, 6, 7]
>>> example
[1, 2, 6, 7]Context
StackExchange Code Review Q#125241, answer score: 2
Revisions (0)
No revisions yet.