0

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'].

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
Satheesh
  • 33
  • 4

3 Answers3

4

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())))
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
1

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.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • 1
    Bonus: 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
1

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...

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264