Skip to content

Adding unit tests for sorting functions, and improving readability on some sorting algorithms #784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 25, 2019
Merged
6 changes: 1 addition & 5 deletions project_euler/problem_01/sol1.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,4 @@
except NameError:
raw_input = input # Python 3
n = int(raw_input().strip())
sum=0
for a in range(3,n):
if(a%3==0 or a%5==0):
sum+=a
print(sum)
print(sum([e for e in range(3, n) if e % 3 == 0 or e % 5 == 0]))
16 changes: 8 additions & 8 deletions sorts/bogosort.py → sorts/bogo_sort.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
"""
This is a pure python implementation of the bogosort algorithm
For doctests run following command:
python -m doctest -v bogosort.py
python -m doctest -v bogo_sort.py
or
python3 -m doctest -v bogosort.py
python3 -m doctest -v bogo_sort.py
For manual testing run:
python bogosort.py
python bogo_sort.py
"""

from __future__ import print_function
import random


def bogosort(collection):
def bogo_sort(collection):
"""Pure implementation of the bogosort algorithm in Python
:param collection: some mutable ordered collection with heterogeneous
comparable items inside
:return: the same collection ordered by ascending
Examples:
>>> bogosort([0, 5, 3, 2, 2])
>>> bogo_sort([0, 5, 3, 2, 2])
[0, 2, 2, 3, 5]
>>> bogosort([])
>>> bogo_sort([])
[]
>>> bogosort([-2, -5, -45])
>>> bogo_sort([-2, -5, -45])
[-45, -5, -2]
"""

Expand All @@ -46,4 +46,4 @@ def isSorted(collection):

user_input = raw_input('Enter numbers separated by a comma:\n').strip()
unsorted = [int(item) for item in user_input.split(',')]
print(bogosort(unsorted))
print(bogo_sort(unsorted))
2 changes: 1 addition & 1 deletion sorts/bucket_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ def bucket_sort(my_list, bucket_size=DEFAULT_BUCKET_SIZE):
if __name__ == "__main__":
user_input = input('Enter numbers separated by a comma:').strip()
unsorted = [float(n) for n in user_input.split(',') if len(user_input) > 0]
print(bucket_sort(unsorted))
print(bucket_sort(unsorted))
16 changes: 8 additions & 8 deletions sorts/cyclesort.py → sorts/cycle_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ def cycle_sort(array):
except NameError:
raw_input = input # Python 3

user_input = raw_input('Enter numbers separated by a comma:\n')
unsorted = [int(item) for item in user_input.split(',')]
n = len(unsorted)
cycle_sort(unsorted)

print("After sort : ")
for i in range(0, n):
print(unsorted[i], end=' ')
user_input = raw_input('Enter numbers separated by a comma:\n')
unsorted = [int(item) for item in user_input.split(',')]
n = len(unsorted)
cycle_sort(unsorted)

print("After sort : ")
for i in range(0, n):
print(unsorted[i], end=' ')
10 changes: 6 additions & 4 deletions sorts/insertion_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ def insertion_sort(collection):
>>> insertion_sort([-2, -5, -45])
[-45, -5, -2]
"""
for index in range(1, len(collection)):
while index > 0 and collection[index - 1] > collection[index]:
collection[index], collection[index - 1] = collection[index - 1], collection[index]
index -= 1

for loop_index in range(1, len(collection)):
insertion_index = loop_index
while insertion_index > 0 and collection[insertion_index - 1] > collection[insertion_index]:
collection[insertion_index], collection[insertion_index - 1] = collection[insertion_index - 1], collection[insertion_index]
insertion_index -= 1

return collection

Expand Down
2 changes: 1 addition & 1 deletion sorts/merge_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ def merge(left, right):

user_input = raw_input('Enter numbers separated by a comma:\n').strip()
unsorted = [int(item) for item in user_input.split(',')]
print(*merge_sort(unsorted), sep=',')
print(*merge_sort(unsorted), sep=',')
2 changes: 1 addition & 1 deletion sorts/merge_sort_fastest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Python implementation of the fastest merge sort algorithm.
Takes an average of 0.6 microseconds to sort a list of length 1000 items.
Best Case Scenario : O(n)
Worst Case Scenario : O(n)
Worst Case Scenario : O(n^2) because native python functions:min, max and remove are already O(n)
'''
from __future__ import print_function

Expand Down
5 changes: 3 additions & 2 deletions sorts/pancake_sort.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Pancake sort algorithm
# Only can reverse array from 0 to i

def pancakesort(arr):
def pancake_sort(arr):
cur = len(arr)
while cur > 1:
# Find the maximum number in arr
Expand All @@ -13,4 +13,5 @@ def pancakesort(arr):
cur -= 1
return arr

print(pancakesort([0,10,15,3,2,9,14,13]))
if __name__ == '__main__':
print(pancake_sort([0,10,15,3,2,9,14,13]))
2 changes: 1 addition & 1 deletion sorts/radix_sort.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def radixsort(lst):
def radix_sort(lst):
RADIX = 10
placement = 1

Expand Down
74 changes: 74 additions & 0 deletions sorts/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from bogo_sort import bogo_sort
from bubble_sort import bubble_sort
from bucket_sort import bucket_sort
from cocktail_shaker_sort import cocktail_shaker_sort
from comb_sort import comb_sort
from counting_sort import counting_sort
from cycle_sort import cycle_sort
from gnome_sort import gnome_sort
from heap_sort import heap_sort
from insertion_sort import insertion_sort
from merge_sort_fastest import merge_sort as merge_sort_fastest
from merge_sort import merge_sort
from pancake_sort import pancake_sort
from quick_sort_3_partition import quick_sort_3partition
from quick_sort import quick_sort
from radix_sort import radix_sort
from random_pivot_quick_sort import quick_sort_random
from selection_sort import selection_sort
from shell_sort import shell_sort
from tim_sort import tim_sort
from topological_sort import topological_sort
from tree_sort import tree_sort
from wiggle_sort import wiggle_sort


TEST_CASES = [
{'input': [8, 7, 6, 5, 4, 3, -2, -5], 'expected': [-5, -2, 3, 4, 5, 6, 7, 8]},
{'input': [-5, -2, 3, 4, 5, 6, 7, 8], 'expected': [-5, -2, 3, 4, 5, 6, 7, 8]},
{'input': [5, 6, 1, 4, 0, 1, -2, -5, 3, 7], 'expected': [-5, -2, 0, 1, 1, 3, 4, 5, 6, 7]},
{'input': [2, -2], 'expected': [-2, 2]},
{'input': [1], 'expected': [1]},
{'input': [], 'expected': []},
]

'''
TODO:
- Fix some broken tests in particular cases (as [] for example),
- Unify the input format: should always be function(input_collection) (no additional args)
- Unify the output format: should always be a collection instead of updating input elements
and returning None
- Rewrite some algorithms in function format (in case there is no function definition)
'''

TEST_FUNCTIONS = [
bogo_sort,
bubble_sort,
bucket_sort,
cocktail_shaker_sort,
comb_sort,
counting_sort,
cycle_sort,
gnome_sort,
heap_sort,
insertion_sort,
merge_sort_fastest,
merge_sort,
pancake_sort,
quick_sort_3partition,
quick_sort,
radix_sort,
quick_sort_random,
selection_sort,
shell_sort,
tim_sort,
topological_sort,
tree_sort,
wiggle_sort,
]


for function in TEST_FUNCTIONS:
for case in TEST_CASES:
result = function(case['input'])
assert result == case['expected'], 'Executed function: {}, {} != {}'.format(function.__name__, result, case['expected'])
4 changes: 2 additions & 2 deletions sorts/timsort.py → sorts/tim_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def merge(left, right):
return [right[0]] + merge(left, right[1:])


def timsort(lst):
def tim_sort(lst):
runs, sorted_runs = [], []
length = len(lst)
new_run = [lst[0]]
Expand Down Expand Up @@ -75,7 +75,7 @@ def timsort(lst):
def main():

lst = [5,9,10,3,-4,5,178,92,46,-18,0,7]
sorted_lst = timsort(lst)
sorted_lst = tim_sort(lst)
print(sorted_lst)

if __name__ == '__main__':
Expand Down
6 changes: 3 additions & 3 deletions sorts/topological_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ def topological_sort(start, visited, sort):
# return sort
return sort


sort = topological_sort('a', [], [])
print(sort)
if __name__ == '__main__':
sort = topological_sort('a', [], [])
print(sort)
5 changes: 3 additions & 2 deletions sorts/tree_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def inorder(root, res):
res.append(root.val)
inorder(root.right,res)

def treesort(arr):
def tree_sort(arr):
# Build BST
if len(arr) == 0:
return arr
Expand All @@ -42,4 +42,5 @@ def treesort(arr):
inorder(root,res)
return res

print(treesort([10,1,3,2,9,14,13]))
if __name__ == '__main__':
print(tree_sort([10,1,3,2,9,14,13]))
18 changes: 8 additions & 10 deletions sorts/wiggle_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ def wiggle_sort(nums):
if (i % 2 == 1) == (nums[i-1] > nums[i]):
nums[i-1], nums[i] = nums[i], nums[i-1]


print("Enter the array elements:\n")
array=list(map(int,input().split()))
print("The unsorted array is:\n")
print(array)
wiggle_sort(array)
print("Array after Wiggle sort:\n")
print(array)


if __name__ == '__main__':
print("Enter the array elements:\n")
array=list(map(int,input().split()))
print("The unsorted array is:\n")
print(array)
wiggle_sort(array)
print("Array after Wiggle sort:\n")
print(array)