كيفية فرز قائمة الكائنات بناءً على سمة الكائنات؟

StackOverflow https://stackoverflow.com/questions/403421

  •  03-07-2019
  •  | 
  •  

سؤال

لدي قائمة بكائنات بايثون التي أرغب في فرزها حسب سمة للكائنات نفسها.تبدو القائمة كما يلي:

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

كل كائن له عدد:

>>> ut[1].count
1L

أحتاج إلى فرز القائمة حسب عدد الأعداد التنازلية.

لقد رأيت عدة طرق لذلك، ولكني أبحث عن أفضل الممارسات في بايثون.

هل كانت مفيدة؟

المحلول

# 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"). ومع ذلك، وهذا قد يعمل على نسخة ما قبل مشغل بايثون، لذلك سيكون من الجميل أن يكون آلية للتراجع. قد ترغب في القيام بما يلي، ثم:

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

يجب أن يلاحظ القراء أن المفتاح = الطريقة:

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

أسرع بعدة مرات من إضافة عوامل المقارنة الغنية إلى الكائنات.لقد فوجئت بقراءة هذا (صفحة 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)

النهج الموجه للكائنات

من الممارسات الجيدة جعل منطق فرز الكائنات، إن أمكن، خاصية للفئة بدلاً من دمجها في كل حالة مطلوب فيها الترتيب.

وهذا يضمن الاتساق ويزيل الحاجة إلى التعليمات البرمجية المعيارية.

كحد أدنى، يجب عليك تحديد __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]

ويبدو مثل الكثير من لائحة الحالات نموذج جانغو مكتب إدارة السجلات.

لماذا لا فرزها في الاستعلام مثل هذا:

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

إضافة عوامل المقارنة الغنية إلى فئة الكائن، ثم استخدام نوع الأسلوب () من القائمة.
انظر مقارنة الغنية في بيثون .


على تحديث : في على الرغم من أن هذه الطريقة ستعمل، وأعتقد أن الحل من ثلاثية الجوانب هو أكثر ملاءمة لحالتك لأن أبسط طريقة

.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top