diff --git a/ciphers/des_ecb.py b/ciphers/des_ecb.py index 4c904294a2d4..021dccec8c0d 100644 --- a/ciphers/des_ecb.py +++ b/ciphers/des_ecb.py @@ -537,21 +537,26 @@ def decrypt(key: str, cipher_text: str) -> str: if mode not in ["e", "d", "k", "q"]: print("Invalid option. Please try again.") continue - if mode == "q": - break - elif mode == "k": - print(f"Generated key: {Des.generate_key()}") - elif mode == "e": - key = input("Enter the key: ").strip() - if len(key) != 16 and not all(char in "0123456789abcdef" for char in key): - print("Invalid key. Please try again.") - continue - input_string = input("Enter the string to encrypt: ").strip() - print(f"Encrypted string: {Des.encrypt(key, input_string)}") - elif mode == "d": - key = input("Enter the key: ").strip() - if len(key) != 16 and not all(char in "0123456789abcdef" for char in key): - print("Invalid key. Please try again.") - continue - cipher_text = input("Enter the cipher text to decrypt: ").strip() - print(f"Decrypted string: {Des.decrypt(key, cipher_text)}") + match mode: + case "q": + break + case "k": + print(f"Generated key: {Des.generate_key()}") + case "e": + key = input("Enter the key: ").strip() + if len(key) != 16 or not all( + char in "0123456789abcdef" for char in key + ): + print("Invalid key. Please try again.") + continue + input_string = input("Enter the string to encrypt: ").strip() + print(f"Encrypted string: {Des.encrypt(key, input_string)}") + case "d": + key = input("Enter the key: ").strip() + if len(key) != 16 or not all( + char in "0123456789abcdef" for char in key + ): + print("Invalid key. Please try again.") + continue + cipher_text = input("Enter the cipher text to decrypt: ").strip() + print(f"Decrypted string: {Des.decrypt(key, cipher_text)}") diff --git a/sorts/recursive_quick_sort.py b/sorts/recursive_quick_sort.py index c29009aca673..f0387d6377ab 100644 --- a/sorts/recursive_quick_sort.py +++ b/sorts/recursive_quick_sort.py @@ -1,18 +1,41 @@ -def quick_sort(data: list) -> list: +from __future__ import annotations + +from typing import Protocol, TypeVar + + +class Comparable(Protocol): + def __lt__(self, other: object, /) -> bool: ... + + +T = TypeVar("T", bound=Comparable) + + +def quick_sort[T: Comparable](data: list[T]) -> list[T]: """ >>> for data in ([2, 1, 0], [2.2, 1.1, 0], "quick_sort"): ... quick_sort(data) == sorted(data) True True True + + >>> quick_sort(["c", "a", "b"]) + ['a', 'b', 'c'] + + >>> quick_sort([2.5, -1, 0.0]) + [-1, 0.0, 2.5] + + >>> quick_sort([1, "a"]) + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'int' and 'str' """ if len(data) <= 1: return data else: return [ - *quick_sort([e for e in data[1:] if e <= data[0]]), + *quick_sort([e for e in data[1:] if not data[0] < e]), data[0], - *quick_sort([e for e in data[1:] if e > data[0]]), + *quick_sort([e for e in data[1:] if data[0] < e]), ] diff --git a/tests/test_sorts.py b/tests/test_sorts.py index df4fbbada4ec..2a419b6adc8f 100644 --- a/tests/test_sorts.py +++ b/tests/test_sorts.py @@ -48,6 +48,7 @@ from sorts.quick_sort_3_partition import three_way_radix_quicksort from sorts.recursive_insertion_sort import rec_insertion_sort from sorts.recursive_mergesort_array import merge +from sorts.recursive_quick_sort import quick_sort as recursive_quick_sort from sorts.reverse_selection import reverse_selection_sort from sorts.reversort import reversort from sorts.selection_sort import selection_sort @@ -117,6 +118,7 @@ def test_intro_sort_heap_fallback_preserves_surrounding_items(max_depth: int) -> pancake_sort, patience_sort, quick_sort, + recursive_quick_sort, reverse_selection_sort, reversort, selection_sort, @@ -196,6 +198,7 @@ def test_rec_insertion_sort(case) -> None: odd_even_transposition, pancake_sort, patience_sort, + recursive_quick_sort, reverse_selection_sort, reversort, selection_sort, @@ -217,6 +220,18 @@ def test_rec_insertion_sort_rejects_non_comparable_items() -> None: rec_insertion_sort([1, "a"], 2) +def test_recursive_quick_sort_mixed_types() -> None: + """``recursive_quick_sort`` handles comparable non-int items. + + It rejects mixed non-comparable types. + """ + assert recursive_quick_sort(["c", "a", "b"]) == ["a", "b", "c"] + assert recursive_quick_sort([2.5, -1, 0.0]) == [-1, 0.0, 2.5] + + with pytest.raises(TypeError): + recursive_quick_sort([1, "a"]) + + def test_bogo_sort_comparable_items() -> None: assert bogo_sort(["c", "a", "b"]) == ["a", "b", "c"] assert bogo_sort([2.5, -1.0, 0.0]) == [-1.0, 0.0, 2.5]