Python: How to sort the letters in a string alphabetically keeping distinction between uppercases and lowercases

I am trying to order the words of a string in a particular way: In my code below the output is "MNWdeorwy" but i would like it to be "deMNorWwy" (so i need to keep the letters ordered despite being upper o lowercases) Could you please help me to understand where I am wrong and why? Thank you

wrd = "MyNewWord"

def order_word(s):
    if s == "":
        return "Invalid String!"
    else:
        c = sorted(s)
        d = ''.join(sorted(c))
        return d

print order_word(wrd)

I would like to precise that my question is different from the following: How to sort the letters in a string alphabetically in Python : in fact, the answers given in the link does not consider the difference between upper and lowercases in a string.

Upvotes: 5

Views: 6687

Answers (3)

zondo
zondo

Reputation: 20336

sorted() sorts based off of the ordinal of each character. Capital letters have ordinals that are lower than all lowercase letters. If you want different behavior, you'll need to define your own key:

c = sorted(s, key=lambda c: (c.lower(), c.islower()))

That way, c would be sorted by ('c', 1) and C is sorted by ('c', 0). Both come before ('d', ...) or ('e', ...) etc., but the capital C is earlier (lower) than the lowercase c.

By the way, you shouldn't say d = "".join(sorted(c)) because c has already been sorted. Just do d = "".join(c)

Upvotes: 9

gboffi
gboffi

Reputation: 25023

If I understand correctly your requirements, you want to sort a string

  1. without changing the case of letters
  2. as if all the letters have the same case

this can be achieved, e.g.,

In [44]: a = 'zWea'

In [45]: sorted(a,key=lambda c:c.upper())
Out[45]: ['a', 'e', 'W', 'z']

In [46]: 

that works because you transform momentarily individual characters during a comparison.

Forgot to mention, you can mix non-alphabetical chars in your string, but a few characters are placed between upper and lower case alphabetical chars (e.g., the ^ caret), so what you get depends on using .lower() or .upper() method of strings,

In [56]: sorted('abCD^',key=lambda c:c.lower())
Out[56]: ['^', 'a', 'b', 'C', 'D']

In [57]: sorted('abCD^',key=lambda c:c.upper())
Out[57]: ['a', 'b', 'C', 'D', '^']

In [58]: 

Upvotes: 3

Kamlesh
Kamlesh

Reputation: 2056

You can also try like this

import re

def natural_sort(wrd): 
    convert = lambda text: int(text) if text.isdigit() else text.lower() 
    final = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return ''.join(sorted(wrd, key = final))

Output:

>>> natural_sort(wrd)
'deMNorwWy'

OR

You can do with third party library for this on PyPI called natsort

https://pypi.python.org/pypi/natsort

Upvotes: 1

Related Questions