If input is like ['z','t','Z','a','b','A','d']
,then after sorting I want to get output like ['a','A','b','d','t','z','Z']
or ['A','a','b','d','t','Z','z']
.

- 107,652
- 25
- 181
- 264

- 33
- 4
-
Possible duplicate of [case-insensitive list sorting, without lowercasing the result?](https://stackoverflow.com/questions/10269701/case-insensitive-list-sorting-without-lowercasing-the-result) – Mad Physicist Jul 25 '19 at 19:18
-
1Do you want order of upper-case and lowercase to be consistent, or stable based on the input list? – Mad Physicist Jul 25 '19 at 19:20
-
I've posted an answer that explicitly addresses both options. – Mad Physicist Jul 25 '19 at 20:00
3 Answers
This will sort always upper-case letter first:
lst = ['z','t','Z','a','b','A','d']
print(sorted(lst, key=lambda k: 2*ord(k.lower()) + k.islower()))
Prints:
['A', 'a', 'b', 'd', 't', 'Z', 'z']
EDIT Thanks to @MadPhysicist in the comments, another variant:
print(sorted(lst, key=lambda k: (k.lower(), k.islower())))

- 168,389
- 15
- 48
- 91
-
2
-
-
-
@AndrejKesely OP specifically stated that `['a','A','b','d','t','z','Z']` is valid output – DeepSpace Jul 25 '19 at 19:25
-
Could be easily changed (if that matters) to lower first by switching to `isupper()` – Tomerikoo Jul 25 '19 at 19:26
-
1@DeepSpace `sorted(['z','t','Z','A','b','a','d'], key=str.lower)` produces `['A', 'a', 'b', 'd', 't', 'z', 'Z']` – Andrej Kesely Jul 25 '19 at 19:27
-
@AndrejKesely Indeed, I guess that's a side-effect of `sorted` using a stable version of quicksort. – DeepSpace Jul 25 '19 at 19:30
-
You could use sorted
's (or list.sort
's) extra keyword - key
. You can pass to key
a function according to which the sort will be performed. So for example:
l = ['z','t','Z','a','b','A','d']
print(sorted(l, key=str.lower))
Gives:
['a', 'A', 'b', 'd', 't', 'z', 'Z']
Note: this will not preserve the order of lower/upper between different letters. It will preserve the order of original input.

- 18,379
- 16
- 47
- 61
-
1Bonus: If you are defining a lambda just to call a function on the object that is passed in, you can just use the static version, in this case for example `(sorted(l, key=str.lower))` – DeepSpace Jul 25 '19 at 19:27
-
1@DeepSpace You are right. I wasn't sure if it can work here. I know that for example I could use just `int`, but since this is an instance method I wan't sure – Tomerikoo Jul 25 '19 at 19:28
-
1@Tomerikoo. That's the beauty of methods in python. They are just regular functions that accept the instance as the first argument, and live in a class'es namespace. `str.lower(somestring)` produces identical results to `somestring.lower()`, if `somestring` is an instance of `str`. – Mad Physicist Jul 25 '19 at 20:02
-
Yep, played with it and got it better now. Thanks a lot for the point-out and explanation! – Tomerikoo Jul 25 '19 at 20:04
There are two options on how this sorting could be done. Option 1 is stable, meaning that the order of elements is preserved regardless of case:
['A', 'b', 'a', 'B'] -> ['A', 'a', 'b', 'B']
The other option is to always put uppercase before or after lowercase:
['A', 'b', 'a', 'B'] -> ['A', 'a', 'B', 'b'] or ['a', 'A', 'b', 'B']
Both are possible with the key
argument to list.sort
(or the builtin sorted
).
A stable sort is simply:
['A', 'b', 'a', 'B'].sort(key=str.lower)
A fully ordered sort requires you to check the original status of the letter, in addition to comparing the lowercased values:
['A', 'b', 'a', 'B'].sort(key=lambda x: (x.lower(), x.islower()))
This uses the fact that a tuples are compared lexicographically, or element-by-element. The first difference determines the order. If two letters have different values for x.lower()
, they will be sorted as usual. If they have the same lowercase representation, x.islower()
will be compared. Since uppercase letters will return 0 and lowercase letters return 1, lowercase letters will come after uppercase. To switch that, invert the sense of the comparison:
['A', 'b', 'a', 'B'].sort(key=lambda x: (x.lower(), not x.islower()))
OR
['A', 'b', 'a', 'B'].sort(key=lambda x: (x.lower(), x.isupper()))
OR
['A', 'b', 'a', 'B'].sort(key=lambda x: (x.lower(), -x.islower()))
etc...

- 107,652
- 25
- 181
- 264