Sort list of objects by attribute, but attribute contains name, numbers and underscores PYTHON

Question:

A user has asked this question on here but it was in regards to a list of strings. I have a list of classes and want to modify the answer in this question:

original thread

Specifically, this code, works exactly the way I want but I need to modify it to work with class attributes not just a list of strings:

import re
## ref: https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
def sort_nicely( l ):
    """ Sort the given list in the way that humans expect.
    """
    convert = lambda text: int(text) if text.isdigit() else text
    alphanum_key = lambda key: [ convert(c.replace("_","")) for c in re.split('([0-9]+)', key) ]
    l.sort( key=alphanum_key )
    return print(l)
    ```

I’ve tried modifying the lambda expression in many ways but no matter how I modify it I always get the following error:

expected string or bytes-like object

Here is where I am currently at, which does not work. Any insights will be much appreciated

import re

class ContainerTest:
    def __init__( self ):
        self.name = ''
        
def sort_nicely( l ):
    """ Sort the given list in the way that humans expect.
    """
    convert = lambda x: x.name, lambda text: int( x ) if x.isdigit() else x
    alphanum_key = lambda key: [ convert( c.replace( "_", "" ) ) for c in re.split( '([0-9]+)', key ) ]
    l.sort( key=alphanum_key )
    return print( l )

items = []

for i in range( 0, 2 ):
    item = ContainerTest()
    item.name = 'test_128_0' + str( i + 1 )
    items.append( item )
for i in range( 0, 2 ):
    item = ContainerTest()
    item.name = 'test_64_0' + str( i + 1 )
    items.append( item )

sort_nicely( items )
Asked By: Fishypants

||

Answers:

If you want to sort your ContainerTest instances by their names (using the logic developed to sort strings), you just need to make the key function you’re sorting with get the attribute from the object it’s being passed. The important variable is the key argument passed to alphanum_key, which will be the item in the list (an instance of the class, in this case).

Try:

alphanum_key = lambda key: [convert( c.replace("_", ""))
                            for c in re.split('([0-9]+)', key.name)]

The change is at the end of the line, where we do the regex split on key.name rather than key.

Answered By: Blckknght
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.