Skip to content

sorts: make algorithms sort any comparable items, not just ints #15234

Description

@priya-sundaram-dev

Many of our sorts/ implementations are written and tested only against list[int], even though most comparison sorts work for any items that support <. This issue collects the small, well-scoped changes that make them correctly typed and tested for the general case — a good batch of beginner-friendly PRs for Hacktoberfest.

The type hint to use

Comparison sorts need items that are orderable, not Any. Model that with a small Protocol and a TypeVar bound to it:

from typing import Protocol


class Comparable(Protocol):
    def __lt__(self, other: object, /) -> bool: ...


def bubble_sort[T: Comparable](collection: list[T]) -> list[T]:
    ...

list[T] (with T bound to Comparable) is more precise than list[Any]: it says "a list of items that can be compared with each other" and preserves the element type in the return.

Note: counting/radix/bucket/pigeonhole sorts are not comparison sorts — they rely on integer keys. Those should keep their integer-specific hints and are out of scope here.

The tests to add

For each comparison sort, cover a comparable non-int type and the failure mode. Add both a doctest and a case in tests/test_sorts.py:

# succeeds: strings are comparable
assert bubble_sort(["c", "a", "b"]) == ["a", "b", "c"]

# succeeds: floats and ints are comparable
assert bubble_sort([2.5, -1, 0.0]) == [-1, 0.0, 2.5]

# raises: mixing non-comparable types must not silently mis-sort
import pytest

with pytest.raises(TypeError):
    bubble_sort([1, "a"])          # '<' not supported between int and str

The TypeError case matters: a sort that "succeeds" on non-comparable input is a correctness bug, so the test should assert the exception rather than a result.

How to contribute

  • Pick one comparison sort from sorts/ (comment which one so we don't double up).
  • Switch Any → the Comparable/TypeVar pattern above.
  • Add the succeed + raise cases as doctests and to tests/test_sorts.py.
  • Keep it to one algorithm per PR so reviews stay quick.
  • Link this issue without closing it: reference it as Part of #15234 or Ref #15234 in your PR description — not Closes/Fixes/Resolves #15234. A closing keyword makes GitHub auto-close this umbrella issue when your PR merges, even though other checkboxes remain. This issue should stay open until every box is checked.

I'll help review these and update the checklist below. Refs #15081.

Sort algorithms that can sort any comparable items

  • adaptive_merge_sort.py
  • bead_sort.py -- not a comparison sort
  • binary_insertion_sort.py
  • bitonic_sort.py -- needs a power-of-two length
  • bogo_sort.py
  • bubble_sort.py
  • bubble_sort_recursive
  • bucket_sort.py -- not a comparison sort
  • circle_sort.py
  • cocktail_shaker_sort.py
  • comb_sort.py
  • counting_sort.py -- not a comparison sort
  • cycle_sort.py
  • cyclic_sort.py
  • double_sort.py
  • dutch_national_flag_sort.py -- expects only 0/1/2
  • exchange_sort.py
  • external_sort.py
  • flash_sort.py -- not a comparison sort
  • gnome_sort.py
  • heap_sort.py
  • insertion_sort.py -- a good reference implementation to study <--
  • intro_sort.py
  • iterative_merge_sort.py
  • kirkpatrick_reisch_sort.py -- not a comparison sort
  • merge_insertion_sort.py
  • merge_sort.py
  • msd_radix_sort.py -- not a comparison sort
  • natural_sort.py
  • odd_even_sort.py
  • odd_even_transposition_parallel.py
  • odd_even_transposition_single_threaded.py
  • pancake_sort.py
  • patience_sort.py
  • pigeon_sort.py -- not a comparison sort
  • pigeonhole_sort.py -- not a comparison sort
  • power_sort.py
  • quick_sort.py
  • quick_sort_3_partition.py
  • radix_sort.py -- not a comparison sort
  • recursive_insertion_sort.py
  • recursive_mergesort_array.py
  • recursive_quick_sort.py
  • reversort.py
  • reverse_selection.py
  • selection_sort.py
  • shell_sort.py
  • shrink_shell_sort.py
  • slowsort.py
  • smoothsort.py
  • stalin_sort.py -- causes data loss!
  • stooge_sort.py
  • strand_sort.py
  • tim_sort.py
  • topological_sort.py -- sorts directed acyclic graphs
  • tree_sort.py
  • unknown_sort.py
  • wiggle_sort.py -- deliberately doesn't fully sort
Pinned by cclauss

Activity

  1. cclauss commented on Sep 9, 2026

    @cclauss
    Member

    @priya-sundaram-dev Which checkboxes can we check above?

  2. snehapriy958 commented on Sep 9, 2026

    @snehapriy958
    Contributor

    I'd like to work on binary_insertion_sort.py.

  3. priya-sundaram-dev commented on Sep 9, 2026

    @priya-sundaram-dev
    ContributorAuthor

    @cclauss Good question — auditing the list against what's already on master:

    Already done → check the box:

    • insertion_sort.py — this is the reference implementation. It defines the Comparable protocol and uses def insertion_sort[T: Comparable](collection: MutableSequence[T]), with doctests that cover int, str, and random mixes. Nothing to do here; it's the pattern the others should copy.

    Close, but not quite → leave unchecked:

    • pancake_sort.py uses def pancake_sort[T](arr: Sequence[T]) — generic, but T is unbounded, so a type checker won't verify that items are orderable. Tightening it to [T: Comparable] is the small change that closes it.

    Should be removed from the list (not comparison sorts): these are distribution/counting sorts that intrinsically require integer (or bucketable) keys, so "any comparable" doesn't apply — bead_sort.py, bucket_sort.py, counting_sort.py, msd_radix_sort.py, pigeon_sort.py, pigeonhole_sort.py, radix_sort.py. Also normal_distribution_quick_sort.md is a docs file, not a sort to type.

    Want me to open a quick PR that (a) checks off insertion_sort.py, (b) tightens pancake_sort.py to [T: Comparable], and (c) strikes the distribution sorts from the checklist so contributors don't claim out-of-scope files?

  4. priya-sundaram-dev commented on Sep 9, 2026

    @priya-sundaram-dev
    ContributorAuthor

    @snehapriy958 Welcome, and thanks for picking one up! binary_insertion_sort.py is a great choice — it's a comparison sort, so it's fully in scope.

    The pattern to copy is insertion_sort.py:

    1. Add a Comparable protocol (a typing.Protocol with __lt__), or import it if a shared one lands first.
    2. Change the signature to a bounded type parameter, e.g. def binary_insertion_sort[T: Comparable](collection: MutableSequence[T]) -> MutableSequence[T]:.
    3. Extend the doctests to cover more than int — add a str case (e.g. sorting ['d','a','c','b']) and a float case, so the "any comparable" behaviour is actually exercised.

    One gotcha specific to binary insertion sort: it uses bisect/manual binary search on the sorted prefix, and comparisons there must go through </> (which Comparable guarantees) rather than assuming numeric keys. If you keep it to those operators you're good. Ping me on the PR and I'll review promptly. 🙂

  5. reopened this on Sep 9, 2026
  6. priya-sundaram-dev commented on Sep 9, 2026

    @priya-sundaram-dev
    ContributorAuthor

    @kadubhumika welcome, glad to have you on this one! Quick coordination so we don't collide: @snehapriy958 has already claimed binary_insertion_sort.py, so grab any other unchecked file from the list above.

    The pattern is the same for each: copy the approach in insertion_sort.py — it uses a Protocol-based Comparable type so the function sorts anything supporting </>, not just ints. Add doctests with a non-int example (e.g. strings or floats) to prove it, and keep the signature generic. One file per PR keeps reviews fast. Ping me on the PR and I'm happy to review.

  7. HarshRajSinghania commented on Sep 9, 2026

    @HarshRajSinghania
    Contributor

    Working on bubble_sort.py — PR is #15240.

  8. hzagaming commented on Sep 9, 2026

    @hzagaming
    Contributor

    I'll work on circle_sort.py.

  9. reopened this on Sep 9, 2026
  10. 113 remaining items

  11. cclauss commented on Oct 3, 2026

    @cclauss
    Member
    • odd_even_transposition_parallel.py
    • recursive_quick_sort.py
  12. cclauss commented on Oct 3, 2026

    @cclauss
    Member

    https://github.com/search?q=repo%3ATheAlgorithms%2FPython+Protocol,+TypeVar

    TODO: We can remove the whole TypeVar step in the following sorts:

    SEPATATE PR:

    • data_structures/heap/heap.py

    Old code:

    from typing import Any, Protocol, TypeVar
    
    
    class Comparable(Protocol):
        def __lt__(self, other: Any, /) -> bool: ...
    
    
    T = TypeVar("T", bound=Comparable)
    
    
    def XYZ_sort[T: Comparable](...):

    New code (remove the import of TypeVar and the line that starts with T = TypeVar:

    from typing import Any, Protocol
    
    
    class Comparable(Protocol):
        def __lt__(self, other: Any, /) -> bool: ...
    
    
    def XYZ_sort[T: Comparable](...):
  13. julietarubis commented on Oct 3, 2026

    @julietarubis
    Contributor

    Hi, I'd like to help with this issue. I can update one of the remaining sorting implementations to support generic comparable values, update the type hints, and add/adjust tests for non-integer inputs. Is there a specific unchecked algorithm you'd recommend I take?

  14. cclauss commented on Oct 4, 2026

    @cclauss
    Member

    @julietarubis, try modifying sorts/strand_sort.py to remove TypeVar as discussed at:

  15. Ethereal49 commented on Oct 5, 2026

    @Ethereal49

    I am working on sorts/odd_even_transposition_parallel.py for the Comparable hints and success/TypeError cases in this tracking issue, including propagating comparison failures from the workers and cleaning them up. This is one algorithm only; I am using AI assistance and will document the validation in the PR.

  16. abhinaypilli88 commented on Oct 5, 2026

    @abhinaypilli88

    I’d like to work on insertion_sort.py for this issue.

  17. iosayin commented on Oct 5, 2026

    @iosayin
    Contributor

    Opened PR #15494 for sorts/binary_insertion_sort.py and PR #15495 for sorts/pancake_sort.py to remove the redundant TypeVar per the checklist above.

  18. iosayin commented on Oct 5, 2026

    @iosayin
    Contributor

    Opened PR #15496 covering sorts/insertion_sort.py, sorts/recursive_insertion_sort.py, sorts/strand_sort.py, and separate PR #15497 for data_structures/heap/heap.py to remove redundant TypeVar per the list.

  19. julietarubis commented on Oct 6, 2026

    @julietarubis
    Contributor

    @julietarubis, try modifying sorts/strand_sort.py to remove TypeVar as discussed at:

    * [sorts: make algorithms sort any comparable items, not just ints #15234 (comment)](https://github.com/TheAlgorithms/Python/issues/15234#issuecomment-5966666197)
    

    Thanks! I’ll work on sorts/strand_sort.py and remove the TypeVar usage following the approach discussed in the linked comment.

  20. tilakraj-hub commented on Oct 11, 2026

    @tilakraj-hub

    Hi! I'd like to work on recursive_quick_sort.py for this issue.

    I'll update the type hints to use the Comparable protocol and a bounded TypeVar, add doctests for strings, floats, and non-comparable mixed types, and add the corresponding tests in tests/test_sorts.py.

    I'll keep the changes limited to this algorithm and submit a separate PR referencing Part of #15234.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions