12

Как отсортировать список объектов по атрибуту объектов?

16

У меня есть список объектов на Python, который я хочу отсортировать по определенному атрибуту каждого объекта. Вот пример списка:

[Tag(name="toe", count=10), Tag(name="leg", count=2), ...]

Как мне отсортировать этот список по атрибуту .count в порядке убывания?

5 ответ(ов)

1

Способ, который может быть наиболее быстрым, особенно если у вас большой список записей, — это использовать operator.attrgetter("count"). Однако это может не работать в старых версиях Python, поэтому было бы неплохо иметь механизм резервирования. Вам может понадобиться сделать следующее:

try: 
    import operator
except ImportError: 
    keyfun = lambda x: x.count  # используем lambda, если модуль operator недоступен
else: 
    keyfun = operator.attrgetter("count")  # используем operator, так как он быстрее, чем lambda

ut.sort(key=keyfun, reverse=True)  # сортируем на месте

Таким образом, вы создаете универсальное решение, которое будет работать даже если модуль operator недоступен, обеспечивая тем самым совместимость с более старыми версиями Python.

1

Согласно вашему вопросу, ключевой метод key=:

ut.sort(key=lambda x: x.count, reverse=True)

в несколько раз быстрее, чем добавление оператора сравнения к объектам. Я сам был удивлён, прочитав это на странице 485 книги "Python in a Nutshell". Вы можете подтвердить это, запустив тесты на следующей программе:

#!/usr/bin/env python
import random

class C:
    def __init__(self, count):
        self.count = count

    def __cmp__(self, other):
        return cmp(self.count, other.count)

longList = [C(random.random()) for i in xrange(1000000)] # около 6.1 секунды
longList2 = longList[:]

longList.sort() # около 52 - 6.1 = 46 секунд
longList2.sort(key=lambda c: c.count) # около 9 - 6.1 = 3 секунды

Мои, весьма минимальные, тесты показывают, что первый способ сортировки работает более чем в 10 раз медленнее, хотя в книге говорится, что в общем случае это только около 5 раз медленнее. Причина этого заключается в высокой оптимизации используемого алгоритма сортировки в Python (timsort).

Тем не менее, довольно странно, что .sort(lambda) быстрее, чем простой .sort(). Я надеюсь, что это когда-нибудь исправят.

0

Ваш код использует функцию sort для сортировки списка объектов ut по атрибуту count в порядке убывания. Для этого вы импортируете attrgetter из модуля operator, который удобен для извлечения атрибутов из объектов.

Чтобы отвечать на ваш вопрос, вот переведённый фрагмент кода на русский:

from operator import attrgetter
ut.sort(key=attrgetter('count'), reverse=True)

В данном примере ut — это список объектов, и метод sort сортирует его по атрибуту count в порядке убывания. Если вам нужно более детальное объяснение или примеры, пожалуйста, уточните ваш вопрос!

0

Объектно-ориентированный подход

Хорошей практикой является размещение логики сортировки объектов в классе, если это применимо, а не в каждом экземпляре, где требуется сортировка.

Это обеспечивает однородность и исключает необходимость в шаблонном коде.

Минимально вам следует реализовать операции __eq__ и __lt__ для корректной работы. После этого вы можете просто использовать sorted(list_of_objects).

class Card(object):

    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __eq__(self, other):
        return self.rank == other.rank and self.suit == other.suit

    def __lt__(self, other):
        return self.rank < other.rank

hand = [Card(10, 'H'), Card(2, 'h'), Card(12, 'h'), Card(13, 'h'), Card(14, 'h')]
hand_order = [c.rank for c in hand]  # [10, 2, 12, 13, 14]

hand_sorted = sorted(hand)
hand_sorted_order = [c.rank for c in hand_sorted]  # [2, 10, 12, 13, 14]

Таким образом, вы можете организовать сортировку объектов без дублирования кода, и ваш класс будет сам управлять своей логикой сортировки.

0

Скорее всего, это выглядит как список экземпляров моделей Django ORM.

Почему бы не отсортировать их на этапе запроса следующим образом:

ut = Tag.objects.order_by('-count')
Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь