Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort list of strings in natural fashion

I have the following:

sorted( ("A","a","b","B","CC","c"), key=lambda x: x.lower() )

Which gives:

['A', 'a', 'b', 'B', 'c', 'CC']

How do I sort it like this:

['a', 'A', 'b', 'B', 'c', 'CC']

where if there are two values the same, the lower form comes first - a before A.

I'm guessing I do something like this:

sorted( ("A","a","b","B","CC","c"), key=lambda x: (x.lower(),x) )

but this gives A before a:

['A', 'a', 'B', 'b', 'c', 'CC']

How do I do the opposite?

UPDATE

To clarify things further, the following strings: ["A","a","aA","aa"] should be sorted as:

["a","A","aa","aA"]

So "aa" before "aA" and "aaA" before "aAa" etc.

So:

lst = ["A","aA","aa","aaa","aAa","aaA","b","B","CC","c"]

should sort to:

['A', 'aa', 'aA', 'aaa', 'aaA', 'aAa', 'b', 'B', 'c', 'CC']
like image 683
Baz Avatar asked Jan 17 '19 16:01

Baz


2 Answers

You could do:

lst = ["A","a","b","B","CC","c"]

result = sorted(lst, key= lambda x: (x.lower(), not x.islower()))
print(result)

Output

['a', 'A', 'b', 'B', 'c', 'CC']

UPDATE

Given the new you examples you could use the following key:

lst = ["A", "aA", "aa", "aaa", "aAa", "aaA", "b", "B", "CC", "c"]
result = sorted(lst, key=lambda x: (x.lower(), ''.join(str(c.isupper()) for c in x)))
print(result)

Output

['A', 'aa', 'aA', 'aaa', 'aaA', 'aAa', 'b', 'B', 'c', 'CC']

For the other example (["A","a","aA","aa"]) it gives:

['a', 'A', 'aa', 'aA']
like image 107
Dani Mesejo Avatar answered Oct 01 '22 02:10

Dani Mesejo


Here is one way:

sorted( lst, key=lambda x: (x.lower(), *map(str.isupper, x)) )
#['A', 'aa', 'aA', 'aaa', 'aaA', 'aAa', 'b', 'B', 'c', 'CC']

First sort by case insensitive letter. Then call str.upper on all the characters of each string as the second sort condition. This will rank lower case letters first for the same length strings.

Python 2 Version

The above syntax only works in python3, but you can equivalently do the following in python2:

sorted( lst, key=lambda x: ((x.lower(),) + tuple(map(str.isupper, x))) )
like image 28
pault Avatar answered Oct 01 '22 00:10

pault