Skip to main content

py_cryptic_sorter — Multi-Criteria String Sort

Difficulty: hard

Sort a list of strings according to the following criteria, in order:

  1. Primary: by string length (shortest first).
  2. Secondary: ASCII order, except letters are compared case-insensitively (for strings of the same length).
  3. Tertiary: by number of vowels, ascending (for same length and lexically equal under rule 2).
  4. Equal strings keep their original input order.
def cryptic_sorter(strings: list[str]) -> list[str]:

Examples

>>> cryptic_sorter(["apple", "cat", "banana", "dog", "elephant"])
["cat", "dog", "apple", "banana", "elephant"]

>>> cryptic_sorter(["aaa", "bbb", "AAA", "BBB"])
["aaa", "AAA", "bbb", "BBB"]

>>> cryptic_sorter(["hello", "world", "hi", "test"])
["hi", "test", "hello", "world"]

>>> cryptic_sorter([])
[]

>>> cryptic_sorter([""])
[""]

Solution

Download py_cryptic_sorter.py
def cryptic_sorter(strings: list[str]) -> list[str]:
vowels = set("aeiouAEIOU")

def key(s: str):
return (len(s), s.lower(), sum(1 for c in s if c in vowels))

return sorted(strings, key=key)

How It Works

Goal: Order strings by a composite key with a strict precedence — length, then case-insensitive lex order, then vowel count.

Approach: Build a tuple key (length, lowercased, vowel_count). Python compares tuples lexicographically, so the first differing component decides — which is exactly the precedence the spec asks for. sorted is stable, so the rule-4 requirement (preserve input order for full ties) is satisfied for free.

Step by step:

  1. Define a key(s) returning (len(s), s.lower(), vowel_count).
  2. s.lower() produces the case-insensitive secondary key — its tuple comparison falls through to it only when lengths tie.
  3. Vowel count breaks the next tie when the lowercased forms are also equal ("aaa" vs "AAA").
  4. Stable sort preserves the original order for fully equal keys.

Key concept: Tuple keys for multi-level sorting — Python's tuple comparison is exactly the lexicographic order you'd hand-code, so the cleanest way to express "sort by A, then B, then C" is to return (A, B, C) from the key.