वस्तुओं की एक विशेषता के आधार पर वस्तुओं की सूची को कैसे सॉर्ट करें?


803

मुझे पायथन ऑब्जेक्ट्स की एक सूची मिली है, जिसे मैं खुद ऑब्जेक्ट्स की एक विशेषता द्वारा सॉर्ट करना चाहता हूं। सूची इस प्रकार है:

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

प्रत्येक वस्तु की एक गिनती है:

>>> ut[1].count
1L

मुझे उतरने की संख्या के आधार पर सूची को क्रमबद्ध करना होगा।

मैंने इसके लिए कई तरीके देखे हैं, लेकिन मैं पायथन में सबसे अच्छा अभ्यास ढूंढ रहा हूं।



1
उन लोगों के लिए कैसे हल करें जो पायथन में छंटाई के बारे में अधिक जानकारी की तलाश कर रहे हैं।
जेकेकोमोन

1
ऑपरेटर.टेटगेटर ('एट्रिब्यूट_नाम') के अलावा आप ऑब्जेक्ट जैसे ऑब्जेक्ट का उपयोग भी कर सकते हैं जैसे कि object_list.sort (कुंजी = my_sorting_functor ('my_key')), कार्यान्वयन को जानबूझकर छोड़ देना।
विजय शंकर

जवाबों:


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

कुंजी द्वारा छँटाई पर अधिक ।


1
कोई दिक्कत नहीं है। btw, अगर muhuk सही है और यह Django ऑब्जेक्ट्स की एक सूची है, तो आपको उसके समाधान पर विचार करना चाहिए। हालांकि, वस्तुओं को छांटने के सामान्य मामले के लिए, मेरा समाधान संभवतः सबसे अच्छा अभ्यास है।
त्रिकटीक

43
बड़ी सूचियों पर आपको अपनी कुंजी के रूप में oper.attrgetter ('count') का उपयोग करके बेहतर प्रदर्शन मिलेगा। यह इस उत्तर में लैम्बडा फ़ंक्शन का सिर्फ एक अनुकूलित (निम्न स्तर) रूप है।
डेविड आईक

4
महान जवाब के लिए धन्यवाद। यदि यह शब्दकोशों की सूची है और 'गणना' इसकी कुंजी में से एक है, तो इसे नीचे की तरह बदलना होगा: ut.sort (कुंजी = लैम्ब्डा x: x ['गिनती'], रिवर्स = ट्रू)
dganesh2002

मुझे लगता है कि यह निम्नलिखित अद्यतन का हकदार है: यदि कई क्षेत्रों द्वारा सॉर्ट करने की आवश्यकता है, तो इसे सॉर्ट करने के लिए लगातार कॉल द्वारा प्राप्त किया जा सकता है (), क्योंकि अजगर स्थिर सॉर्ट एल्गोरिथ्म का उपयोग कर रहा है।
zzz777

86

एक तरीका जो सबसे तेज़ हो सकता है, खासकर यदि आपकी सूची में बहुत सारे रिकॉर्ड हैं, तो इसका उपयोग करना है 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

7
यहाँ मैं भ्रम से बचने के लिए "cmpfun" के बजाय "keyfun" चर नाम का उपयोग करूंगा। सॉर्ट () विधि एक तुलना फ़ंक्शन को cmp = तर्क के माध्यम से भी स्वीकार करती है।
एकैहोला

यह काम नहीं करता है यदि ऑब्जेक्ट में गतिशील रूप से जोड़े गए गुण हैं, (यदि आपने विधि के self.__dict__ = {'some':'dict'}बाद किया __init__है)। मुझे नहीं पता कि यह अलग क्यों हुआ, हालांकि।
टूटू

@ ततुका: मैंने कभी भी उदाहरण नहीं बदला है __dict__। ध्यान दें कि "गतिशील रूप से जोड़े गए गुण" और "ऑब्जेक्ट की __dict__विशेषता सेट करना " लगभग रूढ़िवादी अवधारणाएं हैं। मैं ऐसा इसलिए कह रहा हूं क्योंकि आपकी टिप्पणी से यह प्रतीत होता है कि __dict__विशेषता सेट करना गतिशील रूप से विशेषताओं को जोड़ने के लिए एक आवश्यकता है।
त्जोट

@tzot: मैं पर यह सही देख रहा हूँ: github.com/stochastic-technologies/goatfish/blob/master/... और उस iterator यहाँ का उपयोग कर: github.com/TallerTechnologies/dishey/blob/master/app.py#L28 उठाता विशेषता त्रुटि। शायद python3 की वजह से, लेकिन फिर भी ...
tutuca

1
@tzot: अगर मुझे इसका उपयोग समझ में आता है, तो मैं operator.attrgetterकिसी भी संपत्ति के नाम के साथ एक फ़ंक्शन की आपूर्ति कर सकता हूं और एक सॉर्ट किया गया संग्रह वापस कर सकता हूं।
आईब्रीस्ट

64

पाठकों को ध्यान देना चाहिए कि कुंजी = विधि:

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 गुना धीमा है। कारण वे कहते हैं कि अजगर ( टाइमसॉर्ट ) में उपयोग किए जाने वाले अत्यधिक अनुकूलन सॉर्ट एल्गोरिथ्म के कारण है ।

फिर भी, इसका बहुत विषम है कि .sort (लंबो), सादे पुराने .sort () की तुलना में तेज़ है। मुझे उम्मीद है कि वे इसे ठीक कर देंगे।


1
परिभाषित करना __cmp__कॉल करने के बराबर है .sort(cmp=lambda), नहीं .sort(key=lambda), इसलिए यह बिल्कुल भी अजीब नहीं है।
tzot

@tzot बिल्कुल सही है। पहली तरह की वस्तुओं को एक दूसरे के खिलाफ बार-बार तुलना करना पड़ता है। दूसरा सॉर्ट प्रत्येक ऑब्जेक्ट तक केवल एक बार अपनी गिनती मान निकालने के लिए पहुंचता है, और फिर यह एक साधारण संख्यात्मक प्रकार करता है जो अत्यधिक अनुकूलित होता है। एक अधिक उचित तुलना होगी longList2.sort(cmp = cmp)। मैंने इसे आज़माया और इसने लगभग वैसा ही प्रदर्शन किया .sort()। (यह भी ध्यान दें कि "सीएमपी" सॉर्ट पैरामीटर को पायथन 3 में हटा दिया गया था)
ब्रायन रोच

43

वस्तु-उन्मुख दृष्टिकोण

ऑब्जेक्ट को क्रमबद्ध तर्क बनाने के लिए अच्छा अभ्यास है, यदि लागू हो, तो प्रत्येक उदाहरण में आदेश की आवश्यकता के बजाय वर्ग की एक संपत्ति शामिल होती है।

यह स्थिरता सुनिश्चित करता है और बॉयलरप्लेट कोड की आवश्यकता को हटाता है।

कम से कम, आपको इसे काम करने के लिए निर्दिष्ट __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]

1
यही तो मैं ढूंढ रहा था! आप हमें कुछ प्रलेखन को इंगित कर सके यही कारण है कि पर प्रकाश डालता है __eq__और __lt__कम से कम कार्यान्वयन आवश्यकताएँ हैं?
फ्रेंडफएक्स

1
@FriendFX, मेरा मानना है कि यह से गर्भित है इस :•The sort routines are guaranteed to use __lt__() when making comparisons between two objects...
JPP

2
@FriendFX: तुलना और छंटाई के लिए portingguide.readthedocs.io/en/latest/comparison.html देखें
कॉर्नेल मैसन

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

16

यह Django ORM मॉडल के उदाहरणों की एक सूची की तरह दिखता है।

उन्हें इस तरह क्वेरी पर क्यों नहीं छाँटा जाए:

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

यह है, लेकिन django- टैगिंग का उपयोग कर रहा है, इसलिए मैं किसी विशेष क्वेरी सेट के लिए उपयोग द्वारा टैग सेट को हथियाने के लिए बिल्ट-इन का उपयोग कर रहा था, जैसे: Tag.objects.usage_for_queryset (QuerySet, मायने रखता है = सत्य)
Nick Sergeant

11

ऑब्जेक्ट क्लास में समृद्ध तुलना ऑपरेटरों को जोड़ें, फिर सूची के सॉर्ट () विधि का उपयोग करें। अजगर में समृद्ध तुलना
देखें ।


अद्यतन : हालांकि यह विधि काम करेगी, मुझे लगता है कि ट्रिप्टिच से समाधान आपके मामले के लिए बेहतर है क्योंकि रास्ता सरल है।


3

यदि आप जिस विशेषता को क्रमबद्ध करना चाहते हैं वह एक संपत्ति है , तो आप operator.attrgetterसंपत्ति के आयात और उपयोग से बच सकते हैंfget इसके बजाय तरीके ।

उदाहरण के लिए, Circleएक संपत्ति के साथ एक वर्ग के लिए radiusहम circlesरेडी द्वारा की सूची को निम्नानुसार क्रमबद्ध कर सकते हैं:

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

यह सबसे प्रसिद्ध विशेषता नहीं है, लेकिन अक्सर मुझे आयात के साथ एक पंक्ति बचाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.