Python: sort by attributes of a user-defined object object, in custom-defined order with a lambda function

theWholeWeek :

I have a list of custom objects that have two (important) attributes, a state code (TX, CA, NY, etc) and a grade level (PK=preK, ES = Elementary School, etc). I need to sort this list by grade, then alphabetically by state code. What I have now is this:

class myObject:
    def __init__(self, state, grade):
        self.state = state 
        self.grade = grade

myObjects = []
myObjects.append(myObject("KY", "HS"))
myObjects.append(myObject("AL", "ES"))
myObjects.append(myObject("NY", "PK"))
myObjects.append(myObject("CA", "PK"))

possibleGrades = ["PK", "K", "ES", "MS", "HS"]
myObjects.sort(key=lambda x: (x.grade, x.state))

for x in myObjects:
    print("Grade: {}, State: {}".format(x.grade, x.state))

output:

Grade: ES, State: AL
Grade: HS, State: KY
Grade: PK, State: CA
Grade: PK, State: NY

What I want is:

Grade: PK, State: CA
Grade: PK, State: NY
Grade: ES, State: AL
Grade: HS, State: KY

What I have sorts myObjects by grade and then state, but put Elementary School is before PreK because I can't figure out how to specify the order of sort to be possibleGrades. I know that there's a way to use .index like it's used here https://www.geeksforgeeks.org/python-sort-list-according-to-other-list-order/ to sort by a custom order, but I can't figure out how to do that with the attributes of an object. It seems like it should be something like:

standards.sort(key=lambda x: (x.grade, x.state) possibleGrades.index(x))

or, in two passes:

standards.sort(key=lambda x: x.grade possibleGrades.index(x))
standards.sort(key=lambda x: x.state)

But those don't work. I know that you can sort with multiple passes to sort by more than one attribute, I'm not attached to doing it in one pass, that's just the most recent iteration and it strikes me as the kind of thing that Python might be able to do. Worst-case scenario, I could write a whole function with def to sort it, but before I do that, is there some more Pythonic way to sort it with lambdas like I'm trying to do?

jignatius :

Try this:

myObjects.sort(key=lambda x: (possibleGrades.index(x.grade), x.state))

This sorts by index of grade in the list possibleGrades first, then by state.

As suggested by @a_guest you could also build a dictionary from the list, particularly if its a large list, and do a O(1) lookup. Then the code will look like this:

grades = {g: i for i, g in enumerate(possibleGrades)}
myObjects.sort(key=lambda x: (grades[x.grade], x.state))

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=346355&siteId=1