Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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']
like image 333
Demosthene Avatar asked Jan 27 '17 12:01

Demosthene


People also ask

How do you sort an alphanumeric order?

Alphanumeric ordering is done using the current language sort order on the client machine as defined by the operating system (i.e. Windows). The user requests the sort by clicking on the column header. A grid must have column headings in order to be sorted by the user.

How do you sort alphanumeric strings?

you should split the strings in two first; the other part being the integer part, and the other the string part. then first compare the integers - if the integers are not equal, the string that should appear first is the one with the smaller integer part.

How do you sort a list in custom order in Python?

Using sort(), lamba, index(): The sort() function does the required in-place sorting(without creating a separate list to store the sorted order) along with a lambda function with a key to specify the function execution for each pair of tuples, the index() function helps to get the order from our custom list list_2.


3 Answers

You have to retain the alphabetic criterion on the string (minus the last element), and introduce the other criterion: ends by a digit.

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

a more complex but robust way:

sorted(l, key=lambda x: (x[:-1] if len(x)>1 and not x[-1].isdigit() else x,x[-1].isdigit() if x else False))

(fixed the corner case noted by Stefan where the list is made of 1 or 0 sized elements or the ['AB', 'AA'] case)

like image 24
Jean-François Fabre Avatar answered Oct 21 '22 20:10

Jean-François Fabre


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.

like image 131
vishes_shell Avatar answered Oct 21 '22 19:10

vishes_shell


Here's another simple way, just treat 0 as Z:

>>> sorted(l, key=lambda x: x.replace('0', 'Z'))
['CRAT', 'CRA0', 'SRATT', 'SRATW', 'SRAT0', 'SRBTT', 'SRBTW', 'SRBT0']

(I'm assuming there are no zeros earlier in the string, let me know if that's wrong.)

like image 24
Stefan Pochmann Avatar answered Oct 21 '22 21:10

Stefan Pochmann