development

개체의 속성을 기반으로 개체 목록을 정렬하는 방법은 무엇입니까?

big-blog 2020. 9. 30. 09:24
반응형

개체의 속성을 기반으로 개체 목록을 정렬하는 방법은 무엇입니까?


객체 자체의 속성별로 정렬하려는 Python 객체 목록이 있습니다. 목록은 다음과 같습니다.

>>> ut
[<Tag: 128>, <Tag: 2008>, <Tag: <>, <Tag: actionscript>, <Tag: addresses>,
 <Tag: aes>, <Tag: ajax> ...]

각 개체에는 개수가 있습니다.

>>> ut[1].count
1L

내림차순으로 목록을 정렬해야합니다.

이에 대한 몇 가지 방법을 보았지만 Python에서 모범 사례를 찾고 있습니다.


# To sort the list in place...
ut.sort(key=lambda x: x.count, reverse=True)

# To return a new list, use the sorted() built-in function...
newlist = sorted(ut, key=lambda x: x.count, reverse=True)

키별 정렬에 대해 자세히 알아보십시오 .


특히 목록에 많은 레코드가있는 경우 가장 빠른 방법은를 사용하는 것 operator.attrgetter("count")입니다. 그러나 이것은 Python의 사전 연산자 버전에서 실행될 수 있으므로 폴백 메커니즘이 있으면 좋을 것입니다. 다음을 수행 할 수 있습니다.

try: import operator
except ImportError: keyfun= lambda x: x.count # use a lambda if no operator module
else: keyfun= operator.attrgetter("count") # use operator since it's faster than lambda

ut.sort(key=keyfun, reverse=True) # sort in-place

독자는 key = 메소드를 주목해야합니다.

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

객체에 풍부한 비교 연산자를 추가하는 것보다 훨씬 빠릅니다. 이 글을 읽고 놀랐습니다 ( "Python in a Nutshell"의 485 페이지). 이 작은 프로그램에서 테스트를 실행하여이를 확인할 수 있습니다.

#!/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)] #about 6.1 secs
longList2 = longList[:]

longList.sort() #about 52 - 6.1 = 46 secs
longList2.sort(key = lambda c: c.count) #about 9 - 6.1 = 3 secs

나의 아주 최소한의 테스트는 첫 번째 종류가 10 배 이상 느리다는 것을 보여 주지만 책은 일반적으로 약 5 배 느리다고 말합니다. 그들이 말하는 이유는 파이썬에서 사용되는 고도로 최적화 된 정렬 알고리즘 때문입니다 ( timsort ).

그래도 .sort (lambda)가 평범한 오래된 .sort ()보다 빠르다는 것은 매우 이상합니다. 나는 그들이 그것을 고치기를 바랍니다.


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

객체 지향 접근 방식

해당되는 경우 순서가 필요한 각 인스턴스에 통합되는 것보다 객체 정렬 논리를 클래스의 속성으로 만드는 것이 좋습니다.

이렇게하면 일관성이 보장되고 상용구 코드가 필요하지 않습니다.

At a minimum, you should specify __eq__ and __lt__ operations for this to work. Then just use 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]

It looks much like a list of Django ORM model instances.

Why not sort them on query like this:

ut = Tag.objects.order_by('-count')

Add rich comparison operators to the object class, then use sort() method of the list.
See rich comparison in python.


Update: Although this method would work, I think solution from Triptych is better suited to your case because way simpler.


If the attribute you want to sort by is a property, then you can avoid importing operator.attrgetter and use the property's fget method instead.

For example, for a class Circle with a property radius we could sort a list of circles by radii as follows:

result = sorted(circles, key=Circle.radius.fget)

This is not the most well-known feature but often saves me a line with the import.

참고URL : https://stackoverflow.com/questions/403421/how-to-sort-a-list-of-objects-based-on-an-attribute-of-the-objects

반응형