Community Python Snippet
Quick Sort in Three Lines, and Why It's Wrong
Every interview blog shows the cute three-line quicksort. It's a teaching aid that looks elegant and ships bugs: O(n log n) extra memory, quadratic on sorted input, and unstable. Here is the cute version, the in-place version we should actually write, and the version with a randomized pivot.
Quick Sort in Three Lines, and Why It's Wrong
Every interview blog shows the cute three-line quicksort. It's a teaching aid that looks elegant and ships bugs: O(n log n) extra memory, quadratic on sorted input, and unstable. Here is the cute version, the in-place version we should actually write, and the version with a randomized pivot.
By @nathanmurphy
February 13, 2026
·
Updated May 20, 2026
479 views
4
Rate
The three-line version is real code I have seen in code reviews and even in shipping production scripts. It is a useful teaching aid because the recursion structure is unusually visible, but every list comprehension allocates a fresh list, doubling the asymptotic memory. The bigger problem is the pivot choice: xs[0] on already-sorted input puts every element into greater and the recursion depth becomes O(n), which on a 10k-element sorted list will overflow Python's default recursion limit. The third problem (instability) only matters when sorting tuples by one field while preserving the order of another, but it is the same root cause: equal elements get hoisted into the equal bucket out of input order.
The in-place version is what I would write in an interview if asked for quicksort. The partition step is the standard Lomuto scheme; the median-of-three pivot is the smallest defense against the worst case that a real implementation needs. Without it, sorted or reverse-sorted input still degrades to O(n^2) and overflows the stack on inputs around 1000 elements (Python's default recursion limit). Lomuto is easier to memorize and teach than Hoare partition; for production-grade speed you would prefer Hoare and dual-pivot, but for clarity and correctness Lomuto is the right interview answer.
Randomized pivot is the version I reach for whenever the input distribution is unknown, which in production is most of the time. Picking a random index in [lo, hi] and swapping it into the hi slot lets us reuse the same Lomuto partition as the previous accordion; the only change is two extra lines. The threading of rng through the recursion is the part most three-line versions skip, and it matters because using random.random() means the sort is not reproducible across runs, which makes test failures hard to investigate. Seeding the rng at the top of the call gives both reproducibility and balanced expected partitions. For all-equal arrays the randomization buys you nothing (Lomuto is O(n^2) on duplicates regardless), and for that case three-way Dutch-flag partition is the right next step.
