0

I want to sort a list of some objects by an attribute, but I also want to be able to specify a key when doing the sort (of those attributes). I have seen answers like this, which use the attribute to sort the objects, but I want to allow for other logic of sorting besides (for strings) just alphabetizing. Here is an example class and sort function to show what I mean:

class Pet:
    def __init__(self, name):
        self.name = name

    def __repr__(self): # for readability
        return 'Pet({})'.format(self.name)

def sort_pets(pets, reverse=False):
    pets.sort(reverse=reverse, key=lambda x : x.name)

So with this function, I can sort a list of Pet objects by their name:

>>> pets = [Pet(i) for i in ['Dexter Lewis Cumberbatch', 'Alice', 'Bozo Bob', 'Cy']]
>>> sort_pets(pets)
>>> print(pets)
[Pet(Alice), Pet(Bozo Bob), Pet(Cy), Pet(Dexter Lewis Cumberbatch)]

I can do so alphabetically or reverse alphabetically (using reverse). But I want to have options for sorting the pets (by name) with different logic (like say the name length, number of spaces, last letter, etc.). I can make a key parameter for sort_pets, but I can't pass it to the key parameter of sort, because it is already being used to access the name attribute. Is there anyway to accomplish this?

1 Answer 1

3

You can do this by incorporating the key parameter from sort_pets into the lambda function when finding the attribute of each object:

def sort_pets(pets, reverse=False, key=None):
    if key is None:
        sortkey = lambda x : x.name
    else:
        sortkey = lambda x : key(x.name)
    pets.sort(reverse=reverse, key=sortkey)

So when a key is not passed to sort_pets, the objects are just sorted by their name attribute. If one is passed, you apply that key to each name in order to build a new lambda key function.

Now you can use the key of sort_pets to sort the Pet objects as if you were just looking at the name:

pets = [Pet(i) for i in ['Dexter Lewis Cumberbatch', 'Alice', 'Bozo Bob', 'Cy']]
print(sort_pets(pets))  #no additional sorting
print(sort_pets(pets, key=lambda x : len(x))) #sort by number of characters
print(sort_pets(pets, key=lambda x : len(x.split(' ')[0]))) #sort by length of first name
print(sort_pets(pets, key = lambda x : x[-1])) #sort by last character

Output:

[Pet(Alice), Pet(Bozo Bob), Pet(Cy), Pet(Dexter Lewis Cumberbatch)]
[Pet(Cy), Pet(Alice), Pet(Bozo Bob), Pet(Dexter Lewis Cumberbatch)]
[Pet(Cy), Pet(Bozo Bob), Pet(Alice), Pet(Dexter Lewis Cumberbatch)]
[Pet(Bozo Bob), Pet(Alice), Pet(Dexter Lewis Cumberbatch), Pet(Cy)]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.