कई विशेषताओं द्वारा एक सूची क्रमित करें?


457

मेरे पास सूचियों की एक सूची है:

[[12, 'tall', 'blue', 1],
[2, 'short', 'red', 9],
[4, 'tall', 'blue', 13]]

अगर मैं एक तत्व को क्रमबद्ध करना चाहता हूं, तो लंबा / छोटा तत्व कहें, मैं इसे कर सकता हूं s = sorted(s, key = itemgetter(1))

यदि मैं लम्बे / छोटे और रंग दोनों के आधार पर क्रमबद्ध करना चाहता था , तो मैं हर तत्व के लिए एक बार, दो बार कर सकता था, लेकिन क्या कोई तेज़ तरीका है?



8
यदि आप सूचियों के बजाय tuples का उपयोग करते हैं , तो पायथन ऑर्डर आपके द्वारा चलाए जाने पर बाईं से दाईं ओर प्रविष्टियों द्वारा सॉर्ट करता है sort। यही कारण है, sorted([(4, 2), (0, 3), (0, 1)]) == [(0, 1), (0, 3), (4, 2)]
मतीन उल्हाक

जवाबों:


772

एक कुंजी एक फ़ंक्शन हो सकती है जो एक टपल लौटाती है:

s = sorted(s, key = lambda x: (x[1], x[2]))

या आप उसी का उपयोग करके प्राप्त कर सकते हैं itemgetter(जो तेज़ है और पायथन फ़ंक्शन कॉल से बचा जाता है):

import operator
s = sorted(s, key = operator.itemgetter(1, 2))

और ध्यान दें कि यहां आप उपयोग sortकरने के बजाय उपयोग कर सकते हैं sortedऔर फिर पुन: असाइन कर सकते हैं :

s.sort(key = operator.itemgetter(1, 2))

20
समय से पूर्णता के लिए: मेरे लिए पहली बार हमें 6 प्रति लूप दिया गया और दूसरा 4.4 प्रति लूप
ब्रायन लार्सन

10
क्या पहला आरोही और दूसरा एक अवरोही क्रमबद्ध करने का एक तरीका है? (मान लें कि दोनों विशेषताएं तार हैं, इसलिए -पूर्णांक के लिए जोड़ने जैसे कोई हैक नहीं है )
मार्टिन थोमा

73
कैसे के बारे में अगर मैं revrse=Trueकेवल x[1]यह संभव है लागू करना चाहते हैं?
एमीथ

28
@moose, @Athth, केवल एक विशेषता के विपरीत, आप दो बार सॉर्ट कर सकते हैं: पहले माध्यमिक s = sorted(s, key = operator.itemgetter(2))द्वारा फिर प्राथमिक द्वारा s = sorted(s, key = operator.itemgetter(1), reverse=True)आदर्श नहीं, लेकिन काम करता है।
टामकॉन्सेल

52
@ एमीथ या एक अन्य विकल्प, यदि कुंजी संख्या है, तो इसे उल्टा करने के लिए, आप इसे कई कर सकते हैं -1
सर्ग

37

मुझे यकीन नहीं है कि यह सबसे पायथोनिक विधि है ... मेरे पास ट्यूपल्स की एक सूची थी जो पूर्णांक मूल्यों और 2 वर्णानुक्रम से उतरते हुए 1 को क्रमबद्ध करने की आवश्यकता थी। यह पूर्णांक प्रकार को उलटने की आवश्यकता है लेकिन वर्णानुक्रम प्रकार की नहीं। यहाँ मेरा समाधान था: (एक परीक्षा btw में मक्खी पर, मुझे यह भी पता नहीं था कि आप 'घोंसले' को हल कर सकते हैं)

a = [('Al', 2),('Bill', 1),('Carol', 2), ('Abel', 3), ('Zeke', 2), ('Chris', 1)]  
b = sorted(sorted(a, key = lambda x : x[0]), key = lambda x : x[1], reverse = True)  
print(b)  
[('Abel', 3), ('Al', 2), ('Carol', 2), ('Zeke', 2), ('Bill', 1), ('Chris', 1)]

13
चूंकि 2nd एक संख्या है, यह इसे करने के लिए काम करता है जैसे b = sorted(a, key = lambda x: (-x[1], x[0]))कि अधिक दिखाई देता है जिस पर पहले मानदंड लागू होते हैं। जैसा कि दक्षता के लिए मुझे यकीन नहीं है, किसी को समय की जरूरत है।
आंद्रेई-निकुला पेट्रे

5

पार्टी के लिए कई साल देर हो गई है लेकिन मैं दोनों मानदंडों और उपयोग पर दोनों को क्रमबद्ध करना चाहता हूंreverse=True । यदि कोई और जानना चाहता है, तो आप कोष्ठक में अपने मानदंड (कार्य) लपेट सकते हैं:

s = sorted(my_list, key=lambda i: ( criteria_1(i), criteria_2(i) ), reverse=True)

5

ऐसा प्रतीत होता है कि आप listइसके बजाय एक का उपयोग कर सकते हैंtuple । यह तब और महत्वपूर्ण हो जाता है जब मुझे लगता है कि जब आप सूची / टपल के 'मैजिक इंडेक्स' के बजाय विशेषताओं को पकड़ रहे हैं।

मेरे मामले में मैं एक वर्ग के कई गुणों को क्रमबद्ध करना चाहता था, जहां आने वाली चाबियाँ तार थीं। मुझे अलग-अलग जगहों पर अलग-अलग छंटाई की ज़रूरत थी, और मैं उस मूल वर्ग के लिए एक सामान्य डिफ़ॉल्ट सॉर्ट चाहता था जिसके साथ ग्राहक बातचीत कर रहे थे; केवल 'सॉर्टिंग कीज़' को ओवरराइड करने के बाद जब मुझे वास्तव में 'की आवश्यकता होती है', लेकिन यह भी कि मैं उन्हें उन सूचियों के रूप में संग्रहीत कर सकता हूं जिन्हें क्लास साझा कर सकता है

इसलिए पहले मैंने एक सहायक विधि को परिभाषित किया

def attr_sort(self, attrs=['someAttributeString']:
  '''helper to sort by the attributes named by strings of attrs in order'''
  return lambda k: [ getattr(k, attr) for attr in attrs ]

तो इसका उपयोग करने के लिए

# would defined elsewhere but showing here for consiseness
self.SortListA = ['attrA', 'attrB']
self.SortListB = ['attrC', 'attrA']
records = .... #list of my objects to sort
records.sort(key=self.attr_sort(attrs=self.SortListA))
# perhaps later nearby or in another function
more_records = .... #another list
more_records.sort(key=self.attr_sort(attrs=self.SortListB))

यह सूची के आधार पर उत्पन्न लैम्बडा फ़ंक्शन का उपयोग करेगा object.attrAऔर फिर object.attrBमान लें objectकि प्रदान किए गए स्ट्रिंग नामों के अनुरूप कोई गेटर है। और दूसरे मामले के आधार पर सॉर्ट होता object.attrCतोobject.attrA

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


अच्छा काम। क्या होगा यदि विशेषताओं को अलग-अलग क्रमों में क्रमबद्ध किया जाना चाहिए? मान लीजिए कि एट्ररा को आरोही और एट्र्रिब अवरोही क्रमबद्ध किया जाना चाहिए? क्या इसके शीर्ष पर एक त्वरित समाधान है? धन्यवाद!
mhn_namak

1

यहां एक तरीका है: आप मूल प्रकार के कार्यों की सूची लेने के लिए मूल रूप से अपने सॉर्ट फ़ंक्शन को फिर से लिखते हैं, प्रत्येक सॉर्ट फ़ंक्शन उन विशेषताओं की तुलना करता है जिन्हें आप परीक्षण करना चाहते हैं, प्रत्येक प्रकार के परीक्षण पर, आप देखते हैं और देखते हैं कि क्या सीएमपी फ़ंक्शन एक गैर-शून्य रिटर्न देता है यदि ऐसा है तो रिटर्न वैल्यू को तोड़ें और भेजें। आप इसे लैंबडास की सूची के एक समारोह का लैंबडा कहकर पुकारते हैं।

इसका लाभ यह है कि यह डेटा के माध्यम से एकल पास करता है न कि पिछले प्रकार की तरह जैसा अन्य तरीके करते हैं। एक और बात यह है कि यह जगह में सॉर्ट करता है, जबकि सॉर्ट करने पर लगता है कि यह एक कॉपी है।

मैंने इसे एक रैंक फ़ंक्शन लिखने के लिए उपयोग किया, जो उन कक्षाओं की एक सूची को रैंक करता है जहां प्रत्येक ऑब्जेक्ट एक समूह में होता है और एक स्कोर फ़ंक्शन होता है, लेकिन आप विशेषताओं की किसी भी सूची को जोड़ सकते हैं। संयुक्त राष्ट्र के लैम्ब्डा की तरह ध्यान दें, हालांकि एक सेटर को कॉल करने के लिए लैम्बडा के हैकिश उपयोग। रैंक भाग सूचियों की एक सरणी के लिए काम नहीं करेगा, लेकिन क्रमबद्ध होगा।

#First, here's  a pure list version
my_sortLambdaLst = [lambda x,y:cmp(x[0], y[0]), lambda x,y:cmp(x[1], y[1])]
def multi_attribute_sort(x,y):
    r = 0
    for l in my_sortLambdaLst:
        r = l(x,y)
        if r!=0: return r #keep looping till you see a difference
    return r

Lst = [(4, 2.0), (4, 0.01), (4, 0.9), (4, 0.999),(4, 0.2), (1, 2.0), (1, 0.01), (1, 0.9), (1, 0.999), (1, 0.2) ]
Lst.sort(lambda x,y:multi_attribute_sort(x,y)) #The Lambda of the Lambda
for rec in Lst: print str(rec)

यहाँ वस्तुओं की सूची को रैंक करने का एक तरीका है

class probe:
    def __init__(self, group, score):
        self.group = group
        self.score = score
        self.rank =-1
    def set_rank(self, r):
        self.rank = r
    def __str__(self):
        return '\t'.join([str(self.group), str(self.score), str(self.rank)]) 


def RankLst(inLst, group_lambda= lambda x:x.group, sortLambdaLst = [lambda x,y:cmp(x.group, y.group), lambda x,y:cmp(x.score, y.score)], SetRank_Lambda = lambda x, rank:x.set_rank(rank)):
    #Inner function is the only way (I could think of) to pass the sortLambdaLst into a sort function
    def multi_attribute_sort(x,y):
        r = 0
        for l in sortLambdaLst:
            r = l(x,y)
            if r!=0: return r #keep looping till you see a difference
        return r

    inLst.sort(lambda x,y:multi_attribute_sort(x,y))
    #Now Rank your probes
    rank = 0
    last_group = group_lambda(inLst[0])
    for i in range(len(inLst)):
        rec = inLst[i]
        group = group_lambda(rec)
        if last_group == group: 
            rank+=1
        else:
            rank=1
            last_group = group
        SetRank_Lambda(inLst[i], rank) #This is pure evil!! The lambda purists are gnashing their teeth

Lst = [probe(4, 2.0), probe(4, 0.01), probe(4, 0.9), probe(4, 0.999), probe(4, 0.2), probe(1, 2.0), probe(1, 0.01), probe(1, 0.9), probe(1, 0.999), probe(1, 0.2) ]

RankLst(Lst, group_lambda= lambda x:x.group, sortLambdaLst = [lambda x,y:cmp(x.group, y.group), lambda x,y:cmp(x.score, y.score)], SetRank_Lambda = lambda x, rank:x.set_rank(rank))
print '\t'.join(['group', 'score', 'rank']) 
for r in Lst: print r
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.