Skip to content

Commit 9cae7fc

Browse files
authored
Merge branch 'master' into types/tim-sort-comparable
2 parents c195a81 + 18c82c9 commit 9cae7fc

4 files changed

Lines changed: 91 additions & 9 deletions

File tree

‎sorts/bitonic_sort.py‎

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,16 @@
66

77
from __future__ import annotations
88

9+
from typing import Protocol
910

10-
def comp_and_swap(array: list[int], index1: int, index2: int, direction: int) -> None:
11+
12+
class Comparable(Protocol):
13+
def __lt__(self, other: object, /) -> bool: ...
14+
15+
16+
def comp_and_swap[T: Comparable](
17+
array: list[T], index1: int, index2: int, direction: int
18+
) -> None:
1119
"""Compare the value at given index1 and index2 of the array and swap them as per
1220
the given direction.
1321
@@ -32,13 +40,15 @@ def comp_and_swap(array: list[int], index1: int, index2: int, direction: int) ->
3240
>>> arr
3341
[12, 42, -21, 1]
3442
"""
35-
if (direction == 1 and array[index1] > array[index2]) or (
43+
if (direction == 1 and array[index2] < array[index1]) or (
3644
direction == 0 and array[index1] < array[index2]
3745
):
3846
array[index1], array[index2] = array[index2], array[index1]
3947

4048

41-
def bitonic_merge(array: list[int], low: int, length: int, direction: int) -> None:
49+
def bitonic_merge[T: Comparable](
50+
array: list[T], low: int, length: int, direction: int
51+
) -> None:
4252
"""
4353
It recursively sorts a bitonic sequence in ascending order, if direction = 1, and in
4454
descending if direction = 0.
@@ -62,7 +72,9 @@ def bitonic_merge(array: list[int], low: int, length: int, direction: int) -> No
6272
bitonic_merge(array, low + middle, middle, direction)
6373

6474

65-
def bitonic_sort(array: list[int], low: int, length: int, direction: int) -> None:
75+
def bitonic_sort[T: Comparable](
76+
array: list[T], low: int, length: int, direction: int
77+
) -> None:
6678
"""
6779
This function first produces a bitonic sequence by recursively sorting its two
6880
halves in opposite sorting orders, and then calls bitonic_merge to make them in the
@@ -76,6 +88,22 @@ def bitonic_sort(array: list[int], low: int, length: int, direction: int) -> Non
7688
>>> bitonic_sort(arr, 0, 8, 0)
7789
>>> arr
7890
[145, 92, 34, 12, 0, -23, -121, -167]
91+
92+
>>> arr = ["banana", "apple", "cherry", "date"]
93+
>>> bitonic_sort(arr, 0, 4, 1)
94+
>>> arr
95+
['apple', 'banana', 'cherry', 'date']
96+
97+
>>> arr = [3, 1.5, 2, 4.5]
98+
>>> bitonic_sort(arr, 0, 4, 1)
99+
>>> arr
100+
[1.5, 2, 3, 4.5]
101+
102+
>>> arr = [1, "two", 3, "four"]
103+
>>> bitonic_sort(arr, 0, 4, 1)
104+
Traceback (most recent call last):
105+
...
106+
TypeError: '<' not supported between instances of 'str' and 'int'
79107
"""
80108
if length > 1:
81109
middle = int(length / 2)

‎sorts/patience_sort.py‎

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from bisect import bisect_left
44
from functools import total_ordering
55
from heapq import merge
6+
from typing import Protocol
67

78
"""
89
A pure Python implementation of the patience sort algorithm
@@ -19,16 +20,22 @@
1920
"""
2021

2122

23+
class Comparable(Protocol):
24+
def __lt__(self, other: object, /) -> bool: ...
25+
26+
2227
@total_ordering
23-
class Stack(list):
24-
def __lt__(self, other):
28+
class Stack[T: Comparable](list[T]):
29+
def __lt__(self, other: Stack[T]) -> bool:
2530
return self[-1] < other[-1]
2631

27-
def __eq__(self, other):
32+
def __eq__(self, other: object) -> bool:
33+
if not isinstance(other, Stack):
34+
return NotImplemented
2835
return self[-1] == other[-1]
2936

3037

31-
def patience_sort(collection: list) -> list:
38+
def patience_sort[T: Comparable](collection: list[T]) -> list[T]:
3239
"""A pure implementation of patience sort algorithm in Python
3340
3441
:param collection: some mutable ordered collection with heterogeneous
@@ -44,6 +51,17 @@ def patience_sort(collection: list) -> list:
4451
4552
>>> patience_sort([-3, -17, -48])
4653
[-48, -17, -3]
54+
55+
>>> patience_sort(['d', 'a', 'b', 'e']) == sorted(['d', 'a', 'b', 'e'])
56+
True
57+
58+
>>> patience_sort([3.3, 1.1, 2.2])
59+
[1.1, 2.2, 3.3]
60+
61+
>>> patience_sort([1, "a"]) # doctest: +IGNORE_EXCEPTION_DETAIL
62+
Traceback (most recent call last):
63+
...
64+
TypeError: '<' not supported between instances of 'str' and 'int'
4765
"""
4866
stacks: list[Stack] = []
4967
# sort into stacks

‎sorts/unknown_sort.py‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
already O(n)
66
"""
77

8+
from typing import Protocol
89

9-
def merge_sort(collection: list) -> list:
10+
11+
class Comparable(Protocol):
12+
def __lt__(self, other: object, /) -> bool: ...
13+
14+
15+
def merge_sort[T: Comparable](collection: list[T]) -> list[T]:
1016
"""Pure implementation of the fastest merge sort algorithm in Python
1117
1218
:param collection: some mutable ordered collection with heterogeneous
@@ -22,6 +28,17 @@ def merge_sort(collection: list) -> list:
2228
2329
>>> merge_sort([-2, -5, -45])
2430
[-45, -5, -2]
31+
32+
>>> merge_sort(['d', 'a', 'b', 'e']) == sorted(['d', 'a', 'b', 'e'])
33+
True
34+
35+
>>> merge_sort([1.1, 3.3, 5.5, 2.2, 4.4])
36+
[1.1, 2.2, 3.3, 4.4, 5.5]
37+
38+
>>> merge_sort([1, "a"]) # doctest: +IGNORE_EXCEPTION_DETAIL
39+
Traceback (most recent call last):
40+
...
41+
TypeError: '<' not supported between instances of 'str' and 'int'
2542
"""
2643
start, end = [], []
2744
while len(collection) > 1:

‎tests/test_sorts.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
from sorts.stooge_sort import stooge_sort
5353
from sorts.strand_sort import strand_sort
5454
from sorts.tim_sort import tim_sort
55+
from sorts.unknown_sort import merge_sort as unknown_sort
5556

5657

5758
def test_heap_sort() -> None:
@@ -91,6 +92,7 @@ def test_heap_sort() -> None:
9192
stooge_sort,
9293
strand_sort,
9394
tim_sort,
95+
unknown_sort,
9496
)
9597

9698

@@ -158,11 +160,13 @@ def test_rec_insertion_sort(case) -> None:
158160
odd_even_sort,
159161
odd_even_transposition,
160162
pancake_sort,
163+
patience_sort,
161164
reversort,
162165
selection_sort,
163166
shrink_shell_sort,
164167
strand_sort,
165168
tim_sort,
169+
unknown_sort,
166170
],
167171
ids=lambda f: f.__name__,
168172
)
@@ -182,3 +186,18 @@ def test_bogo_sort_comparable_items() -> None:
182186

183187
with pytest.raises(TypeError):
184188
bogo_sort([1, "a"])
189+
190+
191+
def test_bitonic_sort_comparable_items() -> None:
192+
from sorts.bitonic_sort import bitonic_sort
193+
194+
strings = ["banana", "apple", "cherry", "date"]
195+
bitonic_sort(strings, 0, len(strings), 1)
196+
assert strings == ["apple", "banana", "cherry", "date"]
197+
198+
numbers = [3, 1.5, 2, 4.5]
199+
bitonic_sort(numbers, 0, len(numbers), 1)
200+
assert numbers == [1.5, 2, 3, 4.5]
201+
202+
with pytest.raises(TypeError):
203+
bitonic_sort([1, "two", 3, "four"], 0, 4, 1)

0 commit comments

Comments
 (0)