Search code examples
pythonstringlistsortingalphanumeric

How to custom sort an alphanumeric list?


I have the following list

l = ['SRATT', 'SRATW', 'CRAT', 'CRA0', 'SRBTT', 'SRBTW', 'SRAT0', 'SRBT0']

which I would like to sort alphabetically, with the added rule that a string containing a number at the end (actually always 0) must come after the last fully alphabetical string (last letter is at most W).

How can I do that? (using, if possible, a simple method like sorted)


For this example list, the desired result would be

['CRAT', 'CRA0', 'SRATT', 'SRATW' , 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']

e.g. the following doesn't work

sorted(l, key=lambda x: x[-1].isdigit())

since it puts the strings containing a final number at the end, like so

['SRATT', 'SRATW', 'CRAT', 'SRBTT', 'SRBTW', 'CRA0', 'SRAT0', 'SRBT0']

Solution

  • Working solution at the bottom!

    First attempt:

    >>> l = ['SRATT', 'SRATW', 'CRAT', 'CRA0', 'SRBTT', 'SRBTW', 'SRAT0', 'SRBT0']
    >>> sorted(l, key=lambda x: (x[:-1], x[-1].isdigit()))
    ['CRAT', 'CRA0', 'SRATT', 'SRATW', 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']
    

    UPDATE

    @StefanPochmann said that this will fail with same beginning and different last non-digit character.

    We can add additional element in the end of key, which would be element itself

    >>> l = ['SRATT', 'SRATW', 'CRAT', 'CRA0', 'SRBTT', 'SRBTW', 'SRAT0', 'SRBT0', 'B', 'A']
    >>> sorted(l, key=lambda x: (x[:-1], x[-1].isdigit(), x))
                                                          ^
                                                 additional element
    ['A', 'B', 'CRAT', 'CRA0', 'SRATT', 'SRATW', 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']
    

    UPDATE(final, i hope so)

    @Demosthene noted that the second attempt is not working, and that's true

    So working solution would be to pick any digit at the end of element(if it exist) and change to symbol that is out of letters and digits scope, e.g. '{':

    sorted(l, key=lambda x: ''.join((x[:-1], '{')) if x[-1].isdigit() else x)
    

    or

    sorted(l, key=lambda x: x[:-1] + '{' if x[-1].isdigit() else x)
    

    as @StefanPochmann noted. Which is probably faster.