Program to Sort a List of Numbers in Ascending Order: Complete Python Sorting Algorithm Implementation Guide

Program to sort a list of numbers in ascending order

Sorting is one of those problems every programmer eventually implements from scratch at least once, and then almost never implements from scratch again — because once I understood how Python’s built-in sorting actually works, I realized it’s almost always the better choice over hand-rolled sorting logic. In this guide, I’ll walk through both approaches: using Python’s built-in sorting tools the right way, and implementing a couple of classic sorting algorithms manually to understand what’s actually happening underneath, including their time complexity.

Reading a List of Numbers from the User

Before sorting anything, I need to get the numbers into a list. Here’s the pattern I use most often:

numbers_input = input("Enter numbers separated by spaces: ")
numbers = [int(n) for n in numbers_input.split()]
print("Original list:", numbers)

Example run:

Enter numbers separated by spaces: 9 3 7 1 5
Original list: [9, 3, 7, 1, 5]

.split() breaks the input string into individual pieces on whitespace, and the list comprehension converts each piece into an integer.

Method 1: Using Python’s Built-in sorted() Function

This is the approach I use in almost all real-world code, because it’s fast, well-tested, and requires no manual implementation:

numbers = [9, 3, 7, 1, 5]
sorted_numbers = sorted(numbers)
print("Ascending order:", sorted_numbers)
print("Original list unchanged:", numbers)

Output:

Ascending order: [1, 3, 5, 7, 9]
Original list unchanged: [9, 3, 7, 1, 5]

sorted() is a built-in function that returns a new sorted list, leaving the original untouched. This is important — if I want to sort a list in place instead, without creating a new one, I use the list’s own .sort() method:

numbers = [9, 3, 7, 1, 5]
numbers.sort()
print("Sorted in place:", numbers)

Output:

Sorted in place: [1, 3, 5, 7, 9]

Both sorted() and .sort() accept a reverse=True argument if I want descending order instead:

numbers = [9, 3, 7, 1, 5]
print(sorted(numbers, reverse=True))
# Output: [9, 7, 5, 3, 1]

A Complete Interactive Sorting Program

def sort_numbers():
    numbers_input = input("Enter numbers separated by spaces: ")
    try:
        numbers = [int(n) for n in numbers_input.split()]
    except ValueError:
        print("Please enter valid whole numbers only.")
        return

    ascending = sorted(numbers)
    print("Numbers in ascending order:", ascending)

sort_numbers()

Example run:

Enter numbers separated by spaces: 42 8 15 4 23 16
Numbers in ascending order: [4, 8, 15, 16, 23, 42]

How Python’s Built-in Sort Actually Works Internally

Python’s sorted() and .sort() both use an algorithm called Timsort, developed by Tim Peters specifically for Python (and later adopted by other languages, including Java for object arrays). Timsort is a hybrid sorting algorithm derived from merge sort and insertion sort, specifically designed to perform extremely well on real-world data, which is often partially ordered rather than completely random.

Key facts about Timsort that I find genuinely useful to know:

  • Its worst-case time complexity is O(n log n), the same as merge sort.
  • Its best-case time complexity is O(n), when the input is already sorted or nearly sorted — Timsort detects existing “runs” of ordered data and takes advantage of them, which pure merge sort doesn’t do as efficiently.
  • It’s a stable sort, meaning elements that compare as equal retain their original relative order — this matters a lot when sorting complex objects by one attribute while wanting to preserve order on ties.
people = [("Ali", 25), ("Sara", 30), ("John", 25)]
sorted_people = sorted(people, key=lambda p: p[1])
print(sorted_people)
# Output: [('Ali', 25), ('John', 25), ('Sara', 30)]
# Ali still appears before John because stability preserves their original relative order

Implementing Bubble Sort Manually (For Understanding)

Even though I never use this in real production code, implementing a basic sorting algorithm by hand was genuinely useful for understanding what “sorting” actually costs computationally. Bubble sort repeatedly steps through the list, comparing adjacent elements and swapping them if they’re in the wrong order:

def bubble_sort(arr):
    numbers = arr.copy()
    n = len(numbers)
    for i in range(n):
        swapped = False
        for j in range(0, n - i - 1):
            if numbers[j] > numbers[j + 1]:
                numbers[j], numbers[j + 1] = numbers[j + 1], numbers[j]
                swapped = True
        if not swapped:
            break   # Already sorted -- stop early
    return numbers

numbers = [9, 3, 7, 1, 5]
print(bubble_sort(numbers))
# Output: [1, 3, 5, 7, 9]

Bubble sort has a worst-case and average-case time complexity of O(n²), because for each of the n elements, it potentially scans through nearly the entire remaining list again. For small lists this is unnoticeable, but it becomes dramatically slower than Timsort as the list size grows — this is exactly why I never use it beyond educational purposes.

Implementing Selection Sort Manually

Another classic algorithm — selection sort repeatedly finds the minimum element from the unsorted portion of the list and moves it to the front:

def selection_sort(arr):
    numbers = arr.copy()
    n = len(numbers)
    for i in range(n):
        min_index = i
        for j in range(i + 1, n):
            if numbers[j] < numbers[min_index]:
                min_index = j
        numbers[i], numbers[min_index] = numbers[min_index], numbers[i]
    return numbers

numbers = [9, 3, 7, 1, 5]
print(selection_sort(numbers))
# Output: [1, 3, 5, 7, 9]

Selection sort is also O(n²) in all cases, but unlike bubble sort, it doesn’t benefit from early termination on already-sorted data — it always performs the same number of comparisons regardless of the input’s initial order.

Comparing Performance: Built-in Sort vs Manual Implementations

import random
import time

data = [random.randint(0, 100000) for _ in range(5000)]

start = time.perf_counter()
sorted(data)
print("Built-in sorted():", time.perf_counter() - start)

start = time.perf_counter()
bubble_sort(data)
print("Bubble sort:", time.perf_counter() - start)

When I’ve run comparisons like this myself, the built-in sorted() function is consistently and dramatically faster — often by two or three orders of magnitude on lists of a few thousand elements — because Timsort is implemented in optimized C code within CPython, while my hand-written Python loops carry the overhead of the Python bytecode interpreter for every single comparison and swap.

Sorting with a Custom Key

Real-world sorting often isn’t as simple as plain ascending numbers — I frequently need to sort by some derived value. The key parameter handles this cleanly:

words = ["banana", "kiwi", "apple", "fig"]
sorted_by_length = sorted(words, key=len)
print(sorted_by_length)
# Output: ['fig', 'kiwi', 'apple', 'banana']

numbers = [-9, 3, -7, 1, 5]
sorted_by_absolute = sorted(numbers, key=abs)
print(sorted_by_absolute)
# Output: [1, 3, 5, -7, -9]

Common Mistakes I’ve Made

  • Confusing sorted() and .sort() — using .sort() when I actually needed the original list preserved, or trying to assign the result of .sort() to a variable (.sort() returns None, not the sorted list).
  • Reimplementing sorting manually in production code, not realizing Python’s built-in Timsort is both faster and more thoroughly tested than anything I’d write myself.
  • Forgetting int() conversion when reading numbers from input(), causing lexicographic (string-based) sorting instead of numeric sorting — "10" < "9" is True as strings, which surprises people the first time they see it.
  • Using bubble sort or selection sort on large real datasets, not accounting for how badly O(n²) algorithms scale compared to O(n log n).

Real-World Applications

I use sorted() with a custom key constantly in real projects: sorting a list of file paths by modification date, sorting API results by price or rating, sorting log entries chronologically, or sorting user records alphabetically by last name. Understanding sorting algorithm complexity also matters directly in technical interviews and in situations where I’m evaluating whether a third-party library’s sorting approach is appropriate for very large datasets.

Frequently Asked Questions

What’s the difference between sorted() and .sort()? sorted() returns a new sorted list and leaves the original unchanged; .sort() sorts the list in place and returns None.

What sorting algorithm does Python use internally? Timsort, a hybrid of merge sort and insertion sort, with O(n log n) worst-case and O(n) best-case time complexity.

Should I ever write my own sorting algorithm in real projects? Generally no — Python’s built-in sorted() is faster, more reliable, and more thoroughly tested than a hand-written implementation; manual sorting algorithms are primarily valuable for learning and interviews.

How do I sort numbers entered as strings correctly? Convert each entry to an integer or float with int() or float() before sorting — sorting raw strings compares them lexicographically, not numerically.

Summary

Sorting a list of numbers in Python is, in practice, a one-line task thanks to the built-in sorted() function and Timsort’s excellent real-world performance. But understanding how algorithms like bubble sort and selection sort work by hand — and why they’re O(n²) compared to Timsort’s O(n log n) — gives real insight into why “just use the built-in function” isn’t just convenient advice, it’s actually the objectively better engineering choice in nearly every practical situation.

References

Total
0
Shares

Leave a Reply

Previous Post
Technology tips for troubleshooting

Technology tips for troubleshooting

Next Post
Program to the number count of letters in a given text in python

Program to Count the Number of Letters in a Given Text in Python: Complete Character Counting Implementation

Related Posts