Skip to content

Commit cce4d26

Browse files
authored
fix: type recursive mergesort for comparable items (#15406)
Accept any iterable of mutually comparable items and return a new list. Part of #15234
1 parent 2c3bcdd commit cce4d26

2 files changed

Lines changed: 38 additions & 13 deletions

File tree

sorts/recursive_mergesort_array.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
1-
"""A merge sort which accepts an array as input and recursively
2-
splits an array in half and sorts and combines them.
1+
"""A merge sort which accepts comparable items and recursively
2+
splits them in half, then sorts and combines the halves.
3+
4+
https://en.wikipedia.org/wiki/Merge_sort
35
"""
46

5-
"""https://en.wikipedia.org/wiki/Merge_sort """
7+
from collections.abc import Iterable
8+
from typing import Protocol
9+
10+
11+
class Comparable(Protocol):
12+
def __lt__(self, other: object, /) -> bool: ...
13+
14+
15+
def merge[T: Comparable](collection: Iterable[T]) -> list[T]:
16+
"""Return a new list of ``collection`` sorted in ascending order.
617
18+
The input is copied, so the original iterable is left unchanged.
19+
Items must be mutually comparable with ``<``.
720
8-
def merge(arr: list[int]) -> list[int]:
9-
"""Return a sorted array.
1021
>>> merge([10,9,8,7,6,5,4,3,2,1])
1122
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1223
>>> merge([1,2,3,4,5,6,7,8,9,10])
@@ -17,19 +28,30 @@ def merge(arr: list[int]) -> list[int]:
1728
[100]
1829
>>> merge([])
1930
[]
31+
>>> merge(["c", "a", "b"])
32+
['a', 'b', 'c']
33+
>>> merge([2.5, -1, 0.0])
34+
[-1, 0.0, 2.5]
35+
>>> values = [3, 1, 2]
36+
>>> merge(values)
37+
[1, 2, 3]
38+
>>> values
39+
[3, 1, 2]
40+
>>> merge(("b", "c", "a"))
41+
['a', 'b', 'c']
42+
>>> merge([1, "a"])
43+
Traceback (most recent call last):
44+
...
45+
TypeError: '<' not supported between instances of 'int' and 'str'
2046
"""
47+
arr = list(collection)
2148
if len(arr) > 1:
2249
middle_length = len(arr) // 2 # Finds the middle of the array
23-
left_array = arr[
24-
:middle_length
25-
] # Creates an array of the elements in the first half.
26-
right_array = arr[
27-
middle_length:
28-
] # Creates an array of the elements in the second half.
50+
# Sort each half into a new list, then combine those halves in ``arr``.
51+
left_array = merge(arr[:middle_length])
52+
right_array = merge(arr[middle_length:])
2953
left_size = len(left_array)
3054
right_size = len(right_array)
31-
merge(left_array) # Starts sorting the left.
32-
merge(right_array) # Starts sorting the right
3355
left_index = 0 # Left Counter
3456
right_index = 0 # Right Counter
3557
index = 0 # Position Counter

tests/test_sorts.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
from sorts.patience_sort import patience_sort
4242
from sorts.quick_sort import quick_sort
4343
from sorts.recursive_insertion_sort import rec_insertion_sort
44+
from sorts.recursive_mergesort_array import merge
4445
from sorts.reversort import reversort
4546
from sorts.selection_sort import selection_sort
4647
from sorts.shell_sort import shell_sort
@@ -70,6 +71,7 @@ def test_heap_sort() -> None:
7071
heap_sort,
7172
insertion_sort,
7273
iter_merge_sort,
74+
merge,
7375
merge_sort,
7476
odd_even_sort,
7577
pancake_sort,
@@ -140,6 +142,7 @@ def test_rec_insertion_sort(case) -> None:
140142
exchange_sort,
141143
gnome_sort,
142144
insertion_sort,
145+
merge,
143146
merge_sort,
144147
odd_even_sort,
145148
pancake_sort,

0 commit comments

Comments
 (0)