diff --git a/sorts/bubble_sort.py b/sorts/bubble_sort.py index c66d5d59dd93..817ea262007c 100644 --- a/sorts/bubble_sort.py +++ b/sorts/bubble_sort.py @@ -1,7 +1,12 @@ -from typing import Any +from typing import Protocol -def bubble_sort_iterative(collection: list[Any]) -> list[Any]: +class Comparable(Protocol): + def __lt__(self, other: object, /) -> bool: ... + + + +def bubble_sort_iterative[T: Comparable](collection: list[T]) -> list[T]: """Pure implementation of the bubble sort algorithm in Python (iterative). Bubble sort works by repeatedly stepping through the collection, @@ -50,6 +55,10 @@ def bubble_sort_iterative(collection: list[Any]) -> list[Any]: [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7] >>> bubble_sort_iterative([1, 3.3, 5, 7.7, 2, 4.4, 6]) [1, 2, 3.3, 4.4, 5, 6, 7.7] + >>> bubble_sort_iterative([1, "a"]) + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' >>> import random >>> collection_arg = random.sample(range(-50, 50), 100) >>> bubble_sort_iterative(collection_arg) == sorted(collection_arg) @@ -63,7 +72,7 @@ def bubble_sort_iterative(collection: list[Any]) -> list[Any]: for i in reversed(range(length)): swapped = False for j in range(i): - if collection[j] > collection[j + 1]: + if collection[j + 1] < collection[j]: swapped = True collection[j], collection[j + 1] = collection[j + 1], collection[j] if not swapped: @@ -71,7 +80,7 @@ def bubble_sort_iterative(collection: list[Any]) -> list[Any]: return collection -def bubble_sort_recursive(collection: list[Any]) -> list[Any]: +def bubble_sort_recursive[T: Comparable](collection: list[T]) -> list[T]: """Pure implementation of the bubble sort algorithm in Python (recursive). Functionally identical to the iterative version: each call makes a @@ -114,6 +123,10 @@ def bubble_sort_recursive(collection: list[Any]) -> list[Any]: [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7] >>> bubble_sort_recursive([1, 3.3, 5, 7.7, 2, 4.4, 6]) [1, 2, 3.3, 4.4, 5, 6, 7.7] + >>> bubble_sort_recursive([1, "a"]) + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' >>> bubble_sort_recursive(['a', 'Z', 'B', 'C', 'A', 'c']) ['A', 'B', 'C', 'Z', 'a', 'c'] >>> import random @@ -128,7 +141,7 @@ def bubble_sort_recursive(collection: list[Any]) -> list[Any]: length = len(collection) swapped = False for i in range(length - 1): - if collection[i] > collection[i + 1]: + if collection[i + 1] < collection[i]: collection[i], collection[i + 1] = collection[i + 1], collection[i] swapped = True diff --git a/tests/test_sorts.py b/tests/test_sorts.py index 6de12789dd0a..5a0487ded4e2 100644 --- a/tests/test_sorts.py +++ b/tests/test_sorts.py @@ -17,7 +17,7 @@ import pytest from sorts.binary_insertion_sort import binary_insertion_sort -from sorts.bubble_sort import bubble_sort_iterative +from sorts.bubble_sort import bubble_sort_iterative, bubble_sort_recursive from sorts.circle_sort import circle_sort from sorts.cocktail_shaker_sort import cocktail_shaker_sort from sorts.comb_sort import comb_sort @@ -92,3 +92,9 @@ def test_sort_matches_builtin(sort, case): def test_binary_insertion_sort_rejects_non_comparable_items(): with pytest.raises(TypeError): binary_insertion_sort([1, "a"]) + + +@pytest.mark.parametrize("sort", [bubble_sort_iterative, bubble_sort_recursive]) +def test_bubble_sort_rejects_non_comparable_items(sort): + with pytest.raises(TypeError): + sort([1, "a"])