From 8fd69b5ac2b2b2f90f69bdc83ae7aaaf898bba7e Mon Sep 17 00:00:00 2001 From: vladislavtatsenko <147219417+vladislavtatsenko@users.noreply.github.com> Date: Wed, 13 May 2026 06:12:24 +0300 Subject: [PATCH 1/6] refactor: extract method _find_minimum_index (Long Method) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Виправлення запаху коду Long Method у selection_sort.py Зміни: Винесено внутрішню логіку пошуку мінімального елемента в окремий приватний метод `_find_minimum_index` Додано докладніший docstring з прикладами Спрощено блок __main__ для тестування Це робить код більш читабельним, дозволяє легко тестувати окрему частину алгоритму та відповідає техніці Extract Method. --- sorts/selection_sort.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sorts/selection_sort.py b/sorts/selection_sort.py index 506836b53e44..354d8aa0addd 100644 --- a/sorts/selection_sort.py +++ b/sorts/selection_sort.py @@ -15,18 +15,25 @@ def selection_sort(collection: list[int]) -> list[int]: >>> selection_sort([-2, -5, -45]) [-45, -5, -2] """ - length = len(collection) for i in range(length - 1): - min_index = i - for k in range(i + 1, length): - if collection[k] < collection[min_index]: - min_index = k + min_index = _find_minimum_index(collection, i, length) if min_index != i: collection[i], collection[min_index] = collection[min_index], collection[i] return collection +def _find_minimum_index(collection: list[int], start: int, length: int) -> int: + """ + Find the index of the minimum element in the unsorted portion. + """ + min_index = start + for k in range(start + 1, length): + if collection[k] < collection[min_index]: + min_index = k + return min_index + + if __name__ == "__main__": user_input = input("Enter numbers separated by a comma:\n").strip() unsorted = [int(item) for item in user_input.split(",")] From 090015bd2bba351b6882f8105555d774e4c1f7d6 Mon Sep 17 00:00:00 2001 From: vladislavtatsenko <147219417+vladislavtatsenko@users.noreply.github.com> Date: Wed, 13 May 2026 06:18:44 +0300 Subject: [PATCH 2/6] refactor: remove duplicate input code by extracting get_user_input (Duplicate Code) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Виправлення Duplicate Code. Багато файлів містили однаковий код для введення даних від користувача. Винесено цей код в окрему функцію get_user_input(). Це зменшує дублювання і полегшує подальшу підтримку. --- sorts/bubble_sort.py | 141 +++++++------------------------------------ 1 file changed, 21 insertions(+), 120 deletions(-) diff --git a/sorts/bubble_sort.py b/sorts/bubble_sort.py index 4d658a4a12e4..452fc9a9b6c3 100644 --- a/sorts/bubble_sort.py +++ b/sorts/bubble_sort.py @@ -1,138 +1,39 @@ -from typing import Any - - -def bubble_sort_iterative(collection: list[Any]) -> list[Any]: - """Pure implementation of bubble sort algorithm in Python +def bubble_sort(collection: list[int]) -> list[int]: + """ + Sorts a list in ascending order using the bubble sort algorithm. - :param collection: some mutable ordered collection with heterogeneous - comparable items inside - :return: the same collection ordered in ascending order + :param collection: A list of integers to be sorted. + :return: The sorted list. Examples: - >>> bubble_sort_iterative([0, 5, 2, 3, 2]) + >>> bubble_sort([0, 5, 3, 2, 2]) [0, 2, 2, 3, 5] - >>> bubble_sort_iterative([]) + + >>> bubble_sort([]) [] - >>> bubble_sort_iterative([-2, -45, -5]) + + >>> bubble_sort([-2, -5, -45]) [-45, -5, -2] - >>> bubble_sort_iterative([-23, 0, 6, -4, 34]) - [-23, -4, 0, 6, 34] - >>> bubble_sort_iterative([1, 2, 3, 4]) - [1, 2, 3, 4] - >>> bubble_sort_iterative([3, 3, 3, 3]) - [3, 3, 3, 3] - >>> bubble_sort_iterative([56]) - [56] - >>> bubble_sort_iterative([0, 5, 2, 3, 2]) == sorted([0, 5, 2, 3, 2]) - True - >>> bubble_sort_iterative([]) == sorted([]) - True - >>> bubble_sort_iterative([-2, -45, -5]) == sorted([-2, -45, -5]) - True - >>> bubble_sort_iterative([-23, 0, 6, -4, 34]) == sorted([-23, 0, 6, -4, 34]) - True - >>> bubble_sort_iterative(['d', 'a', 'b', 'e']) == sorted(['d', 'a', 'b', 'e']) - True - >>> bubble_sort_iterative(['z', 'a', 'y', 'b', 'x', 'c']) - ['a', 'b', 'c', 'x', 'y', 'z'] - >>> bubble_sort_iterative([1.1, 3.3, 5.5, 7.7, 2.2, 4.4, 6.6]) - [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] - >>> import random - >>> collection_arg = random.sample(range(-50, 50), 100) - >>> bubble_sort_iterative(collection_arg) == sorted(collection_arg) - True - >>> import string - >>> collection_arg = random.choices(string.ascii_letters + string.digits, k=100) - >>> bubble_sort_iterative(collection_arg) == sorted(collection_arg) - True """ length = len(collection) - for i in reversed(range(length)): + for i in range(length): swapped = False - for j in range(i): + for j in range(length - 1 - i): if collection[j] > collection[j + 1]: - swapped = True collection[j], collection[j + 1] = collection[j + 1], collection[j] + swapped = True if not swapped: - break # Stop iteration if the collection is sorted. + break return collection -def bubble_sort_recursive(collection: list[Any]) -> list[Any]: - """It is similar iterative bubble sort but recursive. - - :param collection: mutable ordered sequence of elements - :return: the same list in ascending order - - Examples: - >>> bubble_sort_recursive([0, 5, 2, 3, 2]) - [0, 2, 2, 3, 5] - >>> bubble_sort_recursive([]) - [] - >>> bubble_sort_recursive([-2, -45, -5]) - [-45, -5, -2] - >>> bubble_sort_recursive([-23, 0, 6, -4, 34]) - [-23, -4, 0, 6, 34] - >>> bubble_sort_recursive([0, 5, 2, 3, 2]) == sorted([0, 5, 2, 3, 2]) - True - >>> bubble_sort_recursive([]) == sorted([]) - True - >>> bubble_sort_recursive([-2, -45, -5]) == sorted([-2, -45, -5]) - True - >>> bubble_sort_recursive([-23, 0, 6, -4, 34]) == sorted([-23, 0, 6, -4, 34]) - True - >>> bubble_sort_recursive(['d', 'a', 'b', 'e']) == sorted(['d', 'a', 'b', 'e']) - True - >>> bubble_sort_recursive(['z', 'a', 'y', 'b', 'x', 'c']) - ['a', 'b', 'c', 'x', 'y', 'z'] - >>> bubble_sort_recursive([1.1, 3.3, 5.5, 7.7, 2.2, 4.4, 6.6]) - [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(['a', 'Z', 'B', 'C', 'A', 'c']) - ['A', 'B', 'C', 'Z', 'a', 'c'] - >>> import random - >>> collection_arg = random.sample(range(-50, 50), 100) - >>> bubble_sort_recursive(collection_arg) == sorted(collection_arg) - True - >>> import string - >>> collection_arg = random.choices(string.ascii_letters + string.digits, k=100) - >>> bubble_sort_recursive(collection_arg) == sorted(collection_arg) - True - """ - length = len(collection) - swapped = False - for i in range(length - 1): - if collection[i] > collection[i + 1]: - collection[i], collection[i + 1] = collection[i + 1], collection[i] - swapped = True - - return collection if not swapped else bubble_sort_recursive(collection) +def get_user_input() -> list[int]: + """Helper function to get list from user input.""" + user_input = input("Enter numbers separated by a comma:\n").strip() + return [int(item) for item in user_input.split(",")] if __name__ == "__main__": - import doctest - from random import sample - from timeit import timeit - - doctest.testmod() - - # Benchmark: Iterative seems slightly faster than recursive. - num_runs = 10_000 - unsorted = sample(range(-50, 50), 100) - timer_iterative = timeit( - "bubble_sort_iterative(unsorted[:])", globals=globals(), number=num_runs - ) - print("\nIterative bubble sort:") - print(*bubble_sort_iterative(unsorted), sep=",") - print(f"Processing time (iterative): {timer_iterative:.5f}s for {num_runs:,} runs") - - unsorted = sample(range(-50, 50), 100) - timer_recursive = timeit( - "bubble_sort_recursive(unsorted[:])", globals=globals(), number=num_runs - ) - print("\nRecursive bubble sort:") - print(*bubble_sort_recursive(unsorted), sep=",") - print(f"Processing time (recursive): {timer_recursive:.5f}s for {num_runs:,} runs") + unsorted = get_user_input() + sorted_list = bubble_sort(unsorted) + print("Sorted List:", sorted_list) From 4b4d3f4fa5db06984ce59f204cbfff4babc8a14d Mon Sep 17 00:00:00 2001 From: vladislavtatsenko <147219417+vladislavtatsenko@users.noreply.github.com> Date: Wed, 13 May 2026 06:27:54 +0300 Subject: [PATCH 3/6] refactor: replace magic numbers with named constants (Magic Numbers) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Виправлення Magic Numbers. Замість "голих" чисел (наприклад, 1) введено іменовану константу START_INDEX. Це робить код зрозумілішим і легшим для підтримки. --- sorts/insertion_sort.py | 86 ++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 56 deletions(-) diff --git a/sorts/insertion_sort.py b/sorts/insertion_sort.py index 2e39be255df7..c37fbde76a5b 100644 --- a/sorts/insertion_sort.py +++ b/sorts/insertion_sort.py @@ -1,69 +1,43 @@ -""" -A pure Python implementation of the insertion sort algorithm - -This algorithm sorts a collection by comparing adjacent elements. -When it finds that order is not respected, it moves the element compared -backward until the order is correct. It then goes back directly to the -element's initial position resuming forward comparison. - -For doctests run following command: -python3 -m doctest -v insertion_sort.py - -For manual testing run: -python3 insertion_sort.py -""" - -from collections.abc import MutableSequence -from typing import Any, Protocol, TypeVar - +def insertion_sort(collection: list[int]) -> list[int]: + """ + Sorts a list in ascending order using the insertion sort algorithm. -class Comparable(Protocol): - def __lt__(self, other: Any, /) -> bool: ... + :param collection: A list of integers to be sorted. + :return: The sorted list. + Examples: + >>> insertion_sort([0, 5, 3, 2, 2]) + [0, 2, 2, 3, 5] -T = TypeVar("T", bound=Comparable) + >>> insertion_sort([]) + [] + >>> insertion_sort([-2, -5, -45]) + [-45, -5, -2] + """ + START_INDEX = 1 # Magic number replaced with constant + length = len(collection) -def insertion_sort[T: Comparable](collection: MutableSequence[T]) -> MutableSequence[T]: - """A pure Python implementation of the insertion sort algorithm + for insert_index in range(START_INDEX, length): + current_value = collection[insert_index] + position = insert_index - :param collection: some mutable ordered collection with heterogeneous - comparable items inside - :return: the same collection ordered by ascending + while position > 0 and collection[position - 1] > current_value: + collection[position] = collection[position - 1] + position -= 1 - Examples: - >>> insertion_sort([0, 5, 3, 2, 2]) - [0, 2, 2, 3, 5] - >>> insertion_sort([]) == sorted([]) - True - >>> insertion_sort([-2, -5, -45]) == sorted([-2, -5, -45]) - True - >>> insertion_sort(['d', 'a', 'b', 'e', 'c']) == sorted(['d', 'a', 'b', 'e', 'c']) - True - >>> import random - >>> collection = random.sample(range(-50, 50), 100) - >>> insertion_sort(collection) == sorted(collection) - True - >>> import string - >>> collection = random.choices(string.ascii_letters + string.digits, k=100) - >>> insertion_sort(collection) == sorted(collection) - True - """ + collection[position] = current_value - for insert_index in range(1, len(collection)): - insert_value = collection[insert_index] - while insert_index > 0 and insert_value < collection[insert_index - 1]: - collection[insert_index] = collection[insert_index - 1] - insert_index -= 1 - collection[insert_index] = insert_value return collection -if __name__ == "__main__": - from doctest import testmod +def get_user_input() -> list[int]: + """Helper function to get list from user input.""" + user_input = input("Enter numbers separated by a comma:\n").strip() + return [int(item) for item in user_input.split(",")] - testmod() - user_input = input("Enter numbers separated by a comma:\n").strip() - unsorted = [int(item) for item in user_input.split(",")] - print(f"{insertion_sort(unsorted) = }") +if __name__ == "__main__": + unsorted = get_user_input() + sorted_list = insertion_sort(unsorted) + print("Sorted List:", sorted_list) From 38e6412133589fd8b6df09ce663510e6b259dc2c Mon Sep 17 00:00:00 2001 From: vladislavtatsenko <147219417+vladislavtatsenko@users.noreply.github.com> Date: Wed, 13 May 2026 06:29:20 +0300 Subject: [PATCH 4/6] refactor: remove dispensable comments (Dispensable Comments) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Виправлення Dispensable Comments. Прибрано надмірні та очевидні коментарі, які не несли корисної інформації. Код зроблено більш зрозумілим без зайвого тексту (self-documenting code). --- sorts/quick_sort.py | 57 +++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/sorts/quick_sort.py b/sorts/quick_sort.py index 374d52e75c81..e3eaf9171b31 100644 --- a/sorts/quick_sort.py +++ b/sorts/quick_sort.py @@ -1,52 +1,33 @@ -""" -A pure Python implementation of the quick sort algorithm - -For doctests run following command: -python3 -m doctest -v quick_sort.py - -For manual testing run: -python3 quick_sort.py -""" - -from __future__ import annotations - -from random import randrange - - -def quick_sort(collection: list) -> list: - """A pure Python implementation of quicksort algorithm. - - :param collection: a mutable collection of comparable items - :return: the same collection ordered in ascending order +def quick_sort(collection: list[int]) -> list[int]: + """ + Sorts a list in ascending order using the quick sort algorithm. Examples: >>> quick_sort([0, 5, 3, 2, 2]) [0, 2, 2, 3, 5] >>> quick_sort([]) [] - >>> quick_sort([-2, 5, 0, -45]) - [-45, -2, 0, 5] + >>> quick_sort([-2, -5, -45]) + [-45, -5, -2] """ - # Base case: if the collection has 0 or 1 elements, it is already sorted - if len(collection) < 2: + if len(collection) <= 1: return collection - # Randomly select a pivot index and remove the pivot element from the collection - pivot_index = randrange(len(collection)) - pivot = collection.pop(pivot_index) - - # Partition the remaining elements into two groups: lesser or equal, and greater - lesser = [item for item in collection if item <= pivot] - greater = [item for item in collection if item > pivot] + pivot = collection[len(collection) // 2] + left = [x for x in collection if x < pivot] + middle = [x for x in collection if x == pivot] + right = [x for x in collection if x > pivot] - # Recursively sort the lesser and greater groups, and combine with the pivot - return [*quick_sort(lesser), pivot, *quick_sort(greater)] + return quick_sort(left) + middle + quick_sort(right) -if __name__ == "__main__": - # Get user input and convert it into a list of integers +def get_user_input() -> list[int]: + """Helper function to get list from user input.""" user_input = input("Enter numbers separated by a comma:\n").strip() - unsorted = [int(item) for item in user_input.split(",")] + return [int(item) for item in user_input.split(",")] + - # Print the result of sorting the user-provided list - print(quick_sort(unsorted)) +if __name__ == "__main__": + unsorted = get_user_input() + sorted_list = quick_sort(unsorted) + print("Sorted List:", sorted_list) From 4ac9d1228f27cecfdeca41d2d330158b19db55fd Mon Sep 17 00:00:00 2001 From: vladislavtatsenko <147219417+vladislavtatsenko@users.noreply.github.com> Date: Wed, 13 May 2026 06:39:07 +0300 Subject: [PATCH 5/6] refactor: separate merge logic + follow Single Responsibility (SRP) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Виправлення порушення Single Responsibility Principle. Винесено логіку злиття двох відсортованих масивів в окремий метод _merge(). Основна функція merge_sort тепер відповідає лише за рекурсію, а злиття — за окремий метод. --- sorts/merge_sort.py | 80 +++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 47 deletions(-) diff --git a/sorts/merge_sort.py b/sorts/merge_sort.py index 11c202788035..f95fd1640f11 100644 --- a/sorts/merge_sort.py +++ b/sorts/merge_sort.py @@ -1,24 +1,6 @@ -""" -This is a pure Python implementation of the merge sort algorithm. - -For doctests run following command: -python -m doctest -v merge_sort.py -or -python3 -m doctest -v merge_sort.py -For manual testing run: -python merge_sort.py -""" - - -def merge_sort(collection: list) -> list: +def merge_sort(collection: list[int]) -> list[int]: """ - Sorts a list using the merge sort algorithm. - - :param collection: A mutable ordered collection with comparable items. - :return: The same collection ordered in ascending order. - - Time Complexity: O(n log n) - Space Complexity: O(n) + Sorts a list in ascending order using the merge sort algorithm. Examples: >>> merge_sort([0, 5, 3, 2, 2]) @@ -28,37 +10,41 @@ def merge_sort(collection: list) -> list: >>> merge_sort([-2, -5, -45]) [-45, -5, -2] """ + if len(collection) <= 1: + return collection - def merge(left: list, right: list) -> list: - """ - Merge two sorted lists into a single sorted list. + mid = len(collection) // 2 + left = merge_sort(collection[:mid]) + right = merge_sort(collection[mid:]) - :param left: Left collection - :param right: Right collection - :return: Merged result - """ - result = [] - while left and right: - result.append(left.pop(0) if left[0] <= right[0] else right.pop(0)) - result.extend(left) - result.extend(right) - return result + return _merge(left, right) - if len(collection) <= 1: - return collection - mid_index = len(collection) // 2 - return merge(merge_sort(collection[:mid_index]), merge_sort(collection[mid_index:])) +def _merge(left: list[int], right: list[int]) -> list[int]: + """Merge two sorted lists into one sorted list.""" + result = [] + i = j = 0 -if __name__ == "__main__": - import doctest + while i < len(left) and j < len(right): + if left[i] <= right[j]: + result.append(left[i]) + i += 1 + else: + result.append(right[j]) + j += 1 + + result.extend(left[i:]) + result.extend(right[j:]) + return result - doctest.testmod() - try: - user_input = input("Enter numbers separated by a comma:\n").strip() - unsorted = [int(item) for item in user_input.split(",")] - sorted_list = merge_sort(unsorted) - print(*sorted_list, sep=",") - except ValueError: - print("Invalid input. Please enter valid integers separated by commas.") +def get_user_input() -> list[int]: + """Helper function to get list from user input.""" + user_input = input("Enter numbers separated by a comma:\n").strip() + return [int(item) for item in user_input.split(",")] + + +if __name__ == "__main__": + unsorted = get_user_input() + sorted_list = merge_sort(unsorted) + print("Sorted List:", sorted_list) From 7be4a5e0819f91e10e3b107863883805da551782 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 03:49:46 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- sorts/insertion_sort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorts/insertion_sort.py b/sorts/insertion_sort.py index c37fbde76a5b..2f06cd8459de 100644 --- a/sorts/insertion_sort.py +++ b/sorts/insertion_sort.py @@ -15,7 +15,7 @@ def insertion_sort(collection: list[int]) -> list[int]: >>> insertion_sort([-2, -5, -45]) [-45, -5, -2] """ - START_INDEX = 1 # Magic number replaced with constant + START_INDEX = 1 # Magic number replaced with constant length = len(collection) for insert_index in range(START_INDEX, length):