This is a fun little challenge that confronted me recently. I'll provide my answer below, but I'm curious to see whether there are more elegant or efficient solutions.
A delineation of the requirements as they were presented to me:
- Strings are alphanumeric (see test dataset below)
- Strings should be sorted naturally (see this question for explanation)
- Alpha characters should be sorted ahead of numeric characters (i.e. 'abc' before '100')
- Uppercase instances of alpha chars should be sorted ahead of lowercase instances (i.e. 'ABc', 'Abc', 'abc')
Here's a test dataset:
test_cases = [
# (unsorted list, sorted list)
(list('bca'), ['a', 'b', 'c']),
(list('CbA'), ['A', 'b', 'C']),
(list('r0B9a'), ['a', 'B', 'r', '0', '9']),
(['a2', '1a', '10a', 'a1', 'a100'], ['a1', 'a2', 'a100', '1a', '10a']),
(['GAM', 'alp2', 'ALP11', '1', 'alp100', 'alp10', '100', 'alp1', '2'],
['alp1', 'alp2', 'alp10', 'ALP11', 'alp100', 'GAM', '1', '2', '100']),
(list('ra0b9A'), ['A', 'a', 'b', 'r', '0', '9']),
(['Abc', 'abc', 'ABc'], ['ABc', 'Abc', 'abc']),
]
Bonus Test Case
This is inspired by Janne Karila's comment below that the selected answer currently fails (but wouldn't really be a practical concern in my case):
(['0A', '00a', 'a', 'A', 'A0', '00A', '0', 'a0', '00', '0a'],
['A', 'a', 'A0', 'a0', '0', '00', '0A', '00A', '0a', '00a'])
See Question&Answers more detail:
os