Python: сортировка по атрибутам пользовательского объекта-объекта в пользовательском порядке с использованием лямбда-функции - PullRequest
2 голосов
/ 19 марта 2020

У меня есть список пользовательских объектов, которые имеют два (важных) атрибута, код штата (TX, CA, NY, et c) и уровень обучения (PK = preK, ES = Начальная школа, et c). Мне нужно отсортировать этот список по классам, а затем в алфавитном порядке по коду штата. Теперь у меня есть следующее:

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))

вывод:

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

То, что я хочу:

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

То, что у меня есть, сортирует myObjects по классам, а затем состояние, но положить начальную школу до PreK, потому что я не могу понять, как определить порядок сортировки, чтобы быть возможнымGrades. Я знаю, что есть способ использовать .index, как он используется здесь https://www.geeksforgeeks.org/python-sort-list-according-to-other-list-order/ для сортировки по индивидуальному заказу, но я не могу понять, как это сделать с атрибутами объекта. Кажется, что это должно быть что-то вроде:

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

или в два прохода:

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

Но это не работает. Я знаю, что вы можете сортировать по нескольким проходам, чтобы сортировать по нескольким атрибутам, я не привязан к выполнению этого за один проход, это просто самая последняя итерация, и мне кажется, что Python может быть способен сделать. В худшем случае, я мог бы написать целую функцию с def для ее сортировки, но прежде чем я это сделаю, есть ли еще какой-нибудь Pythoni c способ сортировки с лямбдами, как я пытаюсь сделать?

Ответы [ 2 ]

3 голосов
/ 19 марта 2020

Попробуйте это:

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

Сортирует сначала по индексу оценки в списке possibleGrades, а затем по состоянию.

По предложению @a_guest вы также можете создать словарь из списка, особенно если это большой список, и выполните поиск O (1). Тогда код будет выглядеть так:

grades = {g: i for i, g in enumerate(possibleGrades)}
myObjects.sort(key=lambda x: (grades[x.grade], x.state))
0 голосов
/ 19 марта 2020

Вот ответ с использованием предварительно созданного словаря сортировки и functools.partial для встраивания его в функцию ключа с 1 параметром сортировки.

    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"]

    # grade sort attribute is their position in the list
    di_sort = {item: ix for ix, item in enumerate(possibleGrades)}

    print("di_sort:", di_sort)

    def key(x, di_sort):
        """ return a tuple of  (grade sort, state)"""
        return (di_sort.get(x.grade), x.state)


    # sort's `key` function parameter is only expected to take 
    # one parameter, an item in the list, so `key` needs adjusting

    from functools import partial

    key = partial(key, di_sort=di_sort)

    myObjects.sort(key=key)

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

вывод:

di_sort: {'PK': 0, 'K': 1, 'ES': 2, 'MS': 3, 'HS': 4}
Grade: PK, State: CA
Grade: PK, State: NY
Grade: ES, State: AL
Grade: HS, State: KY
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...