2009-11-01 12 views
5

मेरे पास टुपल्स की एक सूची है जो मैं सॉर्ट करने का प्रयास कर रहा हूं और कुछ मदद का उपयोग कर सकता हूं।सहायता सॉर्टिंग: इससे पहले, और उसके बाद

जो फ़ील्ड मैं टुपल्स में सॉर्ट करना चाहता हूं वह "XXX_YYY" जैसा दिखता है। सबसे पहले, मैं XXX मानों को रिवर्स ऑर्डर में समूहित करना चाहता हूं, और फिर, उन समूहों के भीतर, मैं YYY मानों को सामान्य क्रम क्रम में रखना चाहता हूं। (नोट: मैं बस के रूप में खुश हूँ, वास्तव में, इस तरह से टपल में दूसरा आइटम छँटाई, रिवर्स क्रम पहले शब्द, सामान्य आदेश दूसरा।)

यहाँ का एक उदाहरण है कि मैं क्या है और क्या मैं अंत में चाहूंगा ... सुनिश्चित नहीं है कि यह कैसे करें।

mylist = [ 
    (u'community_news', u'Community: News & Information'), 
    (u'kf_video', u'KF: Video'), 
    (u'community_video', u'Community: Video'), 
    (u'kf_news', u'KF: News & Information'), 
    (u'kf_magazine', u'KF: Magazine') 
] 

मैं इस सूची है कि करने के लिए उत्पादन बदल जाएगा पर sort() किसी प्रकार का प्रदर्शन करने के लिए चाहते हैं: मैं इस संभाल करने के लिए एक pythonic तरीका हो सकता है पर शक लेकिन रैप करने के लिए सक्षम नहीं हूँ

sorted = [ 
    (u'kf_magazine', u'KF: Magazine'), 
    (u'kf_news', u'KF: News & Information'), 
    (u'kf_video', u'KF: Video'), 
    (u'community_news', u'Community: News & Information'), 
    (u'community_video', u'Community: Video'), 
] 

इसके चारों ओर मेरा सिर।

उत्तर

8

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

अजगर 2.*, जो अनुकूलन के दोनों तरह (नहीं sort या sorted :-), एक कस्टम तुलना समारोह एक cmp= नामित तर्क के रूप में पारित किया जा सकता करने के लिए एक ही कॉल में दोनों का समर्थन करता है में; या, एक कस्टम कुंजी निष्कर्षण समारोह key= नामित तर्क के रूप में पारित किया जा सकता है। पायथन 3.* में, केवल बाद का विकल्प उपलब्ध है।

यह महत्वपूर्ण रूप से कुंजी निष्कर्षण दृष्टिकोण को समझने लायक है, भले ही आपको लगता है कि आपने अपनी समस्या को केवल कस्टम-तुलना दृष्टिकोण के साथ हल किया है: न केवल प्रदर्शन के लिए, बल्कि भविष्य के लिए साक्ष्य (पायथन 3) और सामान्यता के लिए (key= दृष्टिकोण min, max, itertools.groupby पर भी लागू होता है ... cmp= दृष्टिकोण से कहीं अधिक सामान्य!)।

कुंजी-निष्कर्षण बहुत सरल है जब सभी प्रमुख उप-क्षेत्रों को समान तरीके से क्रमबद्ध किया जाना चाहिए (सभी आरोही, या सभी अवरोही) - आप उन्हें निकालें; यह अभी भी बहुत आसान है अगर उप-क्षेत्र "दूसरी तरफ" जाते हैं तो संख्याएं होती हैं (आप निकालने के दौरान बस अपना संकेत बदलते हैं); नाजुक मामला बिल्कुल आपके पास है - एकाधिक स्ट्रिंग फ़ील्ड जिन्हें तुलनात्मक तरीकों से तुलना की जानी चाहिए।

एक अपनी समस्या का समाधान करने के लिए यथोचित सरल दृष्टिकोण एक छोटे से शिम वर्ग है:

class Reverser(object): 
    def __init__(self, s): self.s = s 
    def __lt__(self, other): return other.s < self.s 
    def __eq__(self, other): return other.s == self.s 

नोट आप केवल __lt__ और __eq__ (< और == ऑपरेटरों) की आपूर्ति करने के लिए है कि - sort और दोस्तों के सभी अन्य संश्लेषण तुलना, यदि आवश्यक हो, उन दोनों के आधार पर।

तो, यह थोड़ा सहायक उपकरण के साथ सशस्त्र, हम आसानी से आगे बढ़ सकते हैं ...:

def getkey(tup): 
    a, b = tup[0].split('_') 
    return Reverser(a), b 

my_list.sort(key=getkey) 

जैसा कि आप देख, एक बार आप reverser और प्रमुख निष्कर्षण अवधारणाओं "मिल", आप अनिवार्य रूप से करने के लिए कोई कीमत अदा कस्टम तुलना के बजाय कुंजी निष्कर्षण का उपयोग करना: कोड जो मैं सुझाता हूं वह रिवर्सर क्लास के लिए 4 कथन है (जिसे आप एक बार लिख सकते हैं और अपने "गुड्स बैग" मॉड्यूल में कहीं भी डाल सकते हैं), तीन मुख्य निष्कर्षण समारोह के लिए, और निश्चित रूप से एक के लिए sort या sorted कॉल - सबसे कॉम्पैक्ट रूप में कस्टम तुलना दृष्टिकोण के कुल आठ बनाम 4 + 1 == 5 (यानी एक साइन परिवर्तन के साथ या तो सीएमपी का उपयोग करने वाला, या स्वैप तर्क के साथ सीएमपी एनटीएस)। तीन कथन कुंजी-निष्कर्षण के फायदे के लिए भुगतान करने के लिए बहुत अधिक मूल्य नहीं हैं! -

प्रदर्शन स्पष्ट रूप से ऐसी छोटी सूची के साथ एक बड़ा मुद्दा नहीं है, लेकिन यहां तक ​​कि मामूली लंबे समय तक (10 गुना) एक ...: अच्छी तरह से लायक "8 लाइनों की मामूली कीमत नहीं बल्कि -

# my_list as in the Q, my_cmp as per top A, getkey as here 

def bycmp(): 
    return sorted(my_list*10, cmp=my_cmp) 

def bykey(): 
    return sorted(my_list*10, key=getkey) 

... 

$ python -mtimeit -s'import so' 'so.bykey()' 
1000 loops, best of 3: 548 usec per loop 
$ python -mtimeit -s'import so' 'so.bycmp()' 
1000 loops, best of 3: 995 usec per loop 

Ie, key= दृष्टिकोण पहले से ही लगभग दो बार (सूची को क्रमबद्ध करने दोगुनी गति से) के एक प्रदर्शन लाभ जब एक 50 मदों की सूची पर काम कर दिखाया जा रहा है 5 से अधिक ", विशेष रूप से मैंने पहले उल्लेख किए गए सभी अन्य फायदों के साथ!

+0

वाह, मुझे आपका समाधान पसंद है। मुझे नहीं पता था कि सीएमपी = दृष्टिकोण के पास ऐसा जुर्माना था। –

+0

@Steven, tx - yep, सभी को समझ में नहीं आता कि क्यों cmp = पायथन 3 में हटा दिया गया था (एक "आकर्षक उपद्रव" के रूप में जो लोगों को प्रदर्शन दंड भुगतने में बाधा डालता है!), यही कारण है कि मैंने इस विस्तृत स्पष्टीकरण को पोस्ट किया, इसलिए धन्यवाद पुष्टि करने के लिए यह मदद कर सकता है! -) –

+2

@Alex: मैं * आपके * उत्तरों में से किसी एक को संपादित करने में संकोच करता हूं लेकिन शायद my_list.key (cmp = my_cmp) my_list.sort (key = getkey) होना चाहिए? –

10
def my_cmp(x, y): 
    x1, x2 = x[0].split('_') 
    y1, y2 = y[0].split('_') 
    return -cmp(x1, y1) or cmp(x2, y2) 

my_list = [ 
    (u'community_news', u'Community: News & Information'), 
    (u'kf_video', u'KF: Video'), 
    (u'community_video', u'Community: Video'), 
    (u'kf_news', u'KF: News & Information'), 
    (u'kf_magazine', u'KF: Magazine') 
] 

sorted_list = [ 
    (u'kf_magazine', u'KF: Magazine'), 
    (u'kf_news', u'KF: News & Information'), 
    (u'kf_video', u'KF: Video'), 
    (u'community_news', u'Community: News & Information'), 
    (u'community_video', u'Community: Video'), 
] 

my_list.sort(cmp=my_cmp) 
assert my_list == sorted_list 
+1

मैं आपके उत्तर पोस्ट करते समय सीएमपी कॉल को अस्वीकार करने के लिए मेरा संपादन करने वाला था। :) – Kylotan

+1

मैंने तुलना को '-cmp (x1, y1) या cmp (x2, y2)' के साथ तुलना को सरल बना दिया है। :) –

+0

आप अपने फ़ंक्शन के शीर्ष पर विभाजित करने के लिए कुंजी तर्क भी पारित कर सकते हैं: my_list.sort (cmp = my_cmp, key = lambda x: x [0] .split ('_')) –

2
>>> def my_cmp(tuple_1, tuple_2): 
    xxx_1, yyy_1 = tuple_1[0].split('_') 
    xxx_2, yyy_2 = tuple_2[0].split('_') 
    if xxx_1 > xxx_2: 
     return -1 
    elif xxx_1 < xxx_2: 
     return 1 
    else: 
     return cmp(yyy_1, yyy_2) 


>>> import pprint 
>>> pprint.pprint(sorted(mylist, my_cmp)) 
[(u'kf_magazine', u'KF: Magazine'), 
(u'kf_news', u'KF: News & Information'), 
(u'kf_video', u'KF: Video'), 
(u'community_news', u'Community: News & Information'), 
(u'community_video', u'Community: Video')] 

नहीं दुनिया में सबसे सुंदर समाधान ...

संबंधित मुद्दे