Skip to content

Commit f350548

Browse files
author
Brett
committed
re organize project structure and include functionality to allow for tests, cleaner project structure and __main__.py included for console usage.
new quick sort algorithm added. unit tests for sorting algorithms and parser tests. extra setup.py functionality added and name renamed to 'sorter' small readme changes.
1 parent 99c66ba commit f350548

File tree

8 files changed

+250
-119
lines changed

8 files changed

+250
-119
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,13 @@ python -m sorter -g 100 -s bubble
3030
- Be careful when using the **Bogo** sorting algorithm, it shuffles
3131
an array and checks it sorted iteratively, larger data sets will take a long time (forever).
3232

33-
```python sorter.py -h``` can be used to view the available arguments possible.
33+
```python -m sorter -h``` can be used to view the available arguments possible.
3434

3535
### Installing
3636

37-
- Clone repository locally
38-
- ```python setup.py build```
39-
- ```python setup.py install```
40-
- Access module from console with ```python -m sorter```
37+
- Clone repository locally.
38+
- ```python setup.py install```.
39+
- Access module from console with ```python -m sorter```.
4140

4241
## Authors
4342

setup.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
from setuptools import setup
1+
from setuptools import setup, find_packages
22

33
setup(
4-
name='py-custom-sorters',
5-
version='0.1.1',
6-
url='https://github.com/becurrie/py-custom-sorters',
7-
license='MIT',
8-
author='becurrie',
4+
name='sorter',
95
author_email='brettecurrie@gmail.com',
10-
description='Sort Integers in the console.',
11-
py_modules=['sorter'],
6+
author='becurrie',
7+
version='0.1.2',
8+
description='sort integers with different sorting algorithms.',
9+
packages=find_packages(),
10+
py_modules=['sorter.sorter'],
11+
entry_points={'console_scripts': ['sorter = sorter.sorter:main']},
12+
license='MIT',
13+
url='https://github.com/becurrie/py-custom-sorters',
14+
keywords=['sorting', 'algorithm', 'console', 'application'],
1215
)

sorter.py

Lines changed: 0 additions & 106 deletions
This file was deleted.
File renamed without changes.

sorter/__main__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import sys
2+
3+
from sorter.sorter import main
4+
5+
if __name__ == "__main__":
6+
# Allow import run through __name__ = __main__ idiom.
7+
main(sys.argv)

sorter/sorter.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import argparse
2+
import os
3+
import sys
4+
import timeit
5+
6+
from sorter.sorts import *
7+
8+
9+
def parse_args(args):
10+
"""Create the parser and add all required arguments before parsing
11+
user input and returning the parser.parse_args() results.
12+
"""
13+
parser = argparse.ArgumentParser(description='sort some integers.')
14+
15+
group = parser.add_mutually_exclusive_group(required=True)
16+
group.add_argument('-i', '--integers', type=int, nargs='+',
17+
help='integer(s) being sorted.')
18+
group.add_argument('-g', '--generate', type=int,
19+
help='generate a random list of integers to sort.')
20+
parser.add_argument('-s', '--sort', type=str, required=True,
21+
choices=['bubble', 'bogo', 'merge', 'selection', 'quick'],
22+
help='type of sort being performed.')
23+
24+
return parser.parse_args(args)
25+
26+
27+
def print_results(sort_type, original_list, sorted_list, time):
28+
"""Print an original list, sorted list and time required to sort the original list."""
29+
print('\tSort Type: [%s]' % str.upper(sort_type))
30+
print('\tOriginal List:')
31+
for original_chunk in print_list_chunks(original_list, 20):
32+
print('\t' + str(original_chunk)[1:-1])
33+
34+
print('\n\tSorted List:')
35+
for sorted_chunk in print_list_chunks(sorted_list, 20):
36+
print('\t' + str(sorted_chunk)[1:-1])
37+
38+
# Print time required to sort list.
39+
print('\tTime(seconds): %s' % time)
40+
41+
42+
def print_list_chunks(integer_list, n):
43+
"""Simple helper method to print out a list in chunks."""
44+
for i in range(0, len(integer_list), n):
45+
yield integer_list[i:i + n]
46+
47+
48+
def generate_integer_list(size):
49+
"""Generate a list of Integers between specified size value."""
50+
integer_list = list()
51+
for i in range(0, size):
52+
integer_list.append(random.randint(0, 1000))
53+
54+
return integer_list
55+
56+
57+
def sort(sort_type, integers):
58+
"""Sort a list of integers based on the type of sort specified."""
59+
if sort_type == 'bubble':
60+
initial = timeit.default_timer()
61+
sorted_list = bubble_sort(integers)
62+
final = timeit.default_timer()
63+
print_results(sort_type, integers, sorted_list, final - initial)
64+
65+
elif sort_type == 'bogo':
66+
initial = timeit.default_timer()
67+
sorted_list = bogo_sort(integers)
68+
final = timeit.default_timer()
69+
print_results(sort_type, integers, sorted_list, final - initial)
70+
71+
elif sort_type == 'selection':
72+
initial = timeit.default_timer()
73+
sorted_list = selection_sort(integers)
74+
final = timeit.default_timer()
75+
print_results(sort_type, integers, sorted_list, final - initial)
76+
77+
elif sort_type == 'merge':
78+
initial = timeit.default_timer()
79+
original = list(integers)
80+
sorted_list = merge_sort(integers)
81+
final = timeit.default_timer()
82+
print_results(sort_type, original, sorted_list, final - initial)
83+
84+
elif sort_type == 'quick':
85+
initial = timeit.default_timer()
86+
original = list(integers)
87+
quick_sort(integers)
88+
final = timeit.default_timer()
89+
90+
# Slightly different print call, quick_sort sorts in place.
91+
# A new list isn't made, args.integers becomes sorted.
92+
print_results(sort_type, original, integers, final - initial)
93+
94+
95+
def main(args):
96+
"""Main method. build arguments, clear console and parse arguments"""
97+
args = parse_args(args[1:])
98+
99+
# Clear system terminal based on operating system name.
100+
if os.name == 'posix':
101+
os.system('clear')
102+
elif os.name == 'nt':
103+
os.system('cls')
104+
105+
# Check for generate argument specified and create random list.
106+
if args.generate:
107+
args.integers = generate_integer_list(args.generate)
108+
109+
# Main sort() method call from main.
110+
sort(args.sort, args.integers)
111+
112+
113+
if __name__ == "__main__":
114+
# Allow import run through __name__ = __main__ idiom.
115+
main(sys.argv)

sorts.py renamed to sorter/sorts.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,53 @@ def bogo_sort(integers):
9595
is_sorted = True
9696

9797
return integers_clone
98+
99+
100+
def quick_sort(integers):
101+
"""Perform a quick sort on a list of integers, selecting a pivot
102+
point, partition all elements into a first and second part while
103+
looping so all elements < pivot are in first part, any elements
104+
> then pivot are in seconds part, recursively sort both half's
105+
and combine.
106+
"""
107+
quick_sort_helper(integers, 0, len(integers) - 1)
108+
109+
110+
def quick_sort_helper(integers, first, last):
111+
"""Small helper method for calling and recursively finding
112+
pivot/split points.
113+
"""
114+
if first < last:
115+
split = quick_sort_partition(integers, first, last)
116+
117+
quick_sort_helper(integers, first, split - 1)
118+
quick_sort_helper(integers, split + 1, last)
119+
120+
121+
def quick_sort_partition(integers, first, last):
122+
"""Generate a correct partition point for the given list of integers."""
123+
pivot_value = integers[first]
124+
125+
left = first + 1
126+
right = last
127+
128+
done = False
129+
while not done:
130+
while left <= right and integers[left] <= pivot_value:
131+
left += 1
132+
133+
while integers[right] >= pivot_value and right >= left:
134+
right -= 1
135+
136+
if right < left:
137+
done = True
138+
else:
139+
temp = integers[left]
140+
integers[left] = integers[right]
141+
integers[right] = temp
142+
143+
temp = integers[first]
144+
integers[first] = integers[right]
145+
integers[right] = temp
146+
147+
return right

test.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import unittest
2+
3+
from sorter.sorts import *
4+
5+
from sorter.sorter import parse_args
6+
7+
8+
class TestParsing(unittest.TestCase):
9+
10+
def test_integers(self):
11+
"""Test the optional one of: integers argument."""
12+
parser = parse_args(['-i', '1', '3', '6', '9', '-s', 'bubble'])
13+
self.assertTrue(parser.integers)
14+
15+
def test_generate(self):
16+
"""Test the optional one of: generate argument."""
17+
parser = parse_args(['-g', '100', '-s', 'bubble'])
18+
self.assertTrue(parser.generate)
19+
20+
def test_sort(self):
21+
"""Test the required sort argument."""
22+
parser = parse_args(['-g', '10', '-s', 'bubble'])
23+
self.assertTrue(parser.sort)
24+
25+
26+
class TestSorts(unittest.TestCase):
27+
28+
def setUp(self):
29+
"""Simple setup function to create the actual/expected
30+
lists that each sort method should produce if working as
31+
intended.
32+
"""
33+
self.actual = [5, 7, 4, 9, 1, 2]
34+
self.expected = [1, 2, 4, 5, 7, 9]
35+
36+
def test_bubble(self):
37+
"""Test the bubble_sort function."""
38+
integers = bubble_sort(self.actual)
39+
self.assertEqual(self.expected, integers)
40+
41+
def test_selection(self):
42+
"""Test the selection_sort function."""
43+
integers = bubble_sort(self.actual)
44+
self.assertEqual(self.expected, integers)
45+
46+
def test_bogo(self):
47+
"""Test the bogo_sort function."""
48+
integers = bogo_sort(self.actual)
49+
self.assertEqual(self.expected, integers)
50+
51+
def test_merge(self):
52+
"""Test the merge_sort function."""
53+
integers = merge_sort(self.actual)
54+
self.assertEqual(self.expected, integers)
55+
56+
def test_quick(self):
57+
"""Test the quick_sort function. This test is slightly different
58+
because the quick_sort method sorts in place and doesn't return
59+
a new sorted list.
60+
"""
61+
clone = self.actual
62+
quick_sort(clone)
63+
self.assertEqual(self.expected, clone)

0 commit comments

Comments
 (0)