पायथन: n सूचियों की सूची बनाने का सबसे तेज़ तरीका


97

इसलिए मैं सोच रहा था कि कैसे सबसे अच्छी सूची तैयार की जाए:

[[],[],[]...]

क्योंकि पायथन मेमोरी में सूचियों के साथ कैसे काम करता है, यह काम नहीं करता है:

[[]]*n

यह बनाता है [[],[],...]लेकिन प्रत्येक तत्व समान सूची है:

d = [[]]*n
d[0].append(1)
#[[1],[1],...]

एक सूची की तरह कुछ काम करता है:

d = [[] for x in xrange(0,n)]

लेकिन यह लूपिंग के लिए पायथन वीएम का उपयोग करता है। क्या कोई निहित लूप का उपयोग करने का कोई तरीका है (इसका लाभ सी में लिखा जा रहा है)?

d = []
map(lambda n: d.append([]),xrange(0,10))

यह वास्तव में धीमी है। :(


1
मुझे आश्चर्य होगा अगर इससे भी तेज कुछ हो d = [[] for x in xrange(0,n)]। आपको या तो पाइथन में स्पष्ट रूप से लूप करना होगा या पाइथन फ़ंक्शन / लैम्डा को बार-बार कॉल करना चाहिए (जो धीमा होना चाहिए)। लेकिन फिर भी उम्मीद है कि कोई व्यक्ति कुछ ऐसा पोस्ट करेगा जो दिखाता है कि मैं गलत हूं :)।
— मैक

1
जब आपने इनसे मापा timeit, तो आपने क्या सीखा?
— S.Lott

मैंने अभी पुष्टि की है कि map(lambda x: [], xrange(n))सूची समझ से धीमी है।
— एंड्रयू क्लार्क

जवाबों:


105

शायद एकमात्र तरीका जो की तुलना में थोड़ा तेज है

d = [[] for x in xrange(n)]

है

from itertools import repeat
d = [[] for i in repeat(None, n)]

इसे intहर पुनरावृत्ति में एक नई वस्तु बनाने की ज़रूरत नहीं है और यह मेरी मशीन पर लगभग 15% तेज है।

संपादित करें : NumPy का उपयोग करके, आप पायथन लूप का उपयोग करने से बच सकते हैं

d = numpy.empty((n, 0)).tolist()

लेकिन यह वास्तव में सूची समझ से 2.5 गुना धीमा है।


कैसे के बारे में map(lambda x:[], repeat(None,n))?
— पॉलमैक्स

3
@Paul: लैंबडा एक्सप्रेशन के फंक्शन कॉल ओवरहेड के कारण यह फिर से धीमा हो जाएगा।
— स्वेन मार्नाच

क्या अब यह अद्यतन नहीं किया जाना चाहिए कि पायथन 3 में यह रेंज अलग है?
— बेरिक

@beruic मैं पहले कोड ब्लॉक में सवाल से कोड को उद्धृत कर रहा हूं, इसलिए इसे बदलने के लिए वास्तव में कोई मतलब नहीं है।
— स्वेन मार्नाच

12

सूची की समझ वास्तव में स्पष्ट लूपिंग ( उदाहरण कार्यों के लिए आउटपुट देखें) कीdis तुलना में अधिक कुशलता से कार्यान्वित की जाती है और जिस mapतरह से प्रत्येक पुनरावृत्ति पर एक अपारदर्शी कॉल करने योग्य वस्तु को लागू करना पड़ता है, जो ओवरहेड ओवरहेड ओवरहेड करता है।

भले ही, [[] for _dummy in xrange(n)]यह करने के लिए सही तरीके से और (सब पर अगर विद्यमान) छोटे से कोई भी विभिन्न अन्य तरीकों के बीच गति मतभेद है चाहिए मायने रखते हैं। जब तक आप अपना अधिकांश समय ऐसा करने में नहीं बिताते हैं - लेकिन उस स्थिति में, आपको इसके बजाय अपने एल्गोरिदम पर काम करना चाहिए। आप इन सूचियों को कितनी बार बनाते हैं?


5
कृपया, _एक चर नाम के रूप में नहीं ! अन्यथा अच्छा जवाब :)
— स्वेन मार्नाच

11
@Sven: क्यों नहीं? इसका उपयोग आमतौर पर अप्रयुक्त चर के लिए किया जाता है (यदि इसे कहा जाता था i, तो मैं एक के लिए देख रहा हूं जहां इसका उपयोग किया जाता है)। एकमात्र नुकसान यह होगा कि यह _आरईपीएल में अंतिम परिणाम को पकड़े हुए छाया है ... और यह केवल 2.x में मामला है जहां सूची में रिसाव है।

बहुत बार नहीं, यही वजह है कि मैं आगे बढ़ा और एक सूची समझ का इस्तेमाल किया। सोचा कि यह देखना दिलचस्प होगा कि लोगों को हालांकि क्या कहना था। मैंने PyCon पर ड्रॉपबॉक्स को इटर्स्टोलिसेमैप के उपयोग के साथ लूप के बजाय एक md5 हैश को बार-बार एक बड़ी मात्रा में अद्यतन करने के लिए देखा, और मैं तब से सी लूप के साथ थोड़ा जुनूनी हो गया।
— munchybunch

12
इसका उपयोग नहीं करने का सबसे महत्वपूर्ण कारण यह है कि यह लोगों को भ्रमित करने के लिए जाता है, जिससे उन्हें लगता है कि यह किसी प्रकार का विशेष वाक्यविन्यास है। और _इंटरएक्टिव इंटरप्रेटर में संघर्ष के अलावा , यह आम गेटटेक्स उर्फ ​​के साथ भी संघर्ष करता है। यदि आप स्पष्ट करना चाहते हैं कि चर एक डमी चर है, तो इसे कॉल करें dummy, नहीं _।
— स्वेन मार्नाच

12

यहाँ दो विधियाँ हैं, एक मीठी और सरल (और वैचारिक), दूसरी और अधिक औपचारिक और कई तरह की स्थितियों में, एक डेटासेट पढ़ने के बाद बढ़ाई जा सकती है।

विधि 1: वैचारिक

X2=[]
X1=[1,2,3]
X2.append(X1)
X3=[4,5,6]
X2.append(X3)
X2 thus has [[1,2,3],[4,5,6]] ie a list of lists. 

विधि 2: औपचारिक और एक्स्टेंसिबल

सूची को अलग-अलग संख्याओं की सूची के रूप में संग्रहित करने का एक और सुरुचिपूर्ण तरीका है - जिसे यह एक फ़ाइल से पढ़ता है। (यहां फ़ाइल में डेटासेट ट्रेन है) ट्रेन एक डेटा-सेट है जिसमें 50 पंक्तियां और 20 कॉलम हैं। अर्थात। ट्रेन [0] मुझे सीएसवी फ़ाइल की पहली पंक्ति देता है, ट्रेन [1] मुझे दूसरी पंक्ति देता है और इसी तरह। मैं कॉलम 0 को छोड़कर एक सूची के रूप में 50 पंक्तियों के साथ डेटासेट को अलग करने में रुचि रखता हूं, जो कि मेरा समझाया गया चर है, इसलिए इसे ऑर्निगल ट्रेन डेटासेट से हटाया जाना चाहिए, और फिर सूची के बाद सूची को स्केल करना होगा - अर्थात सूची की सूची । यहाँ वह कोड है जो ऐसा करता है।

ध्यान दें कि मैं "1" से आंतरिक लूप में पढ़ रहा हूं क्योंकि मैं केवल व्याख्यात्मक चर में रुचि रखता हूं। और मैं दूसरे लूप में X1 = [] को फिर से इनिशियलाइज़ करता हूं, दूसरे X2.append ([0: (len (train [0]) - 1)]) X1 को फिर से और फिर से लिखेंगे - इसके अलावा यह अधिक मेमोरी कुशल है।

X2=[]
for j in range(0,len(train)):
    X1=[]
    for k in range(1,len(train[0])):
        txt2=train[j][k]
        X1.append(txt2)
    X2.append(X1[0:(len(train[0])-1)])

4

सिंटैक्स के नीचे सूची और सूची का उपयोग करने के लिए

     x = [[] for i in range(10)]

यह 1-डी सूची बनाएगा और इसे प्रारंभ करने के लिए [[संख्या] में संख्या डाल देगा और सूची की लंबाई सीमा (लंबाई) में रख देगा

  • सिंटैक्स के नीचे उपयोग की सूची बनाने के लिए।
    x = [[[0] for i in range(3)] for i in range(10)]

यह 10 * 3 आयाम और मान 0 के साथ सूचियों की सूची को इनिशियलाइज़ करेगा

  • तत्व तक पहुंचने / हेरफेर करने के लिए
    x[1][5]=value

2

इसलिए मैंने सबसे तेज़ रास्ता पाने के लिए कुछ गति तुलना की। सूची की समझ वास्तव में बहुत तेज है। पास होने का एकमात्र तरीका सूची के निर्माण के दौरान बाइटकोड से बाहर निकलने से बचने के लिए है। मेरा पहला प्रयास निम्नलिखित विधि थी, जो सिद्धांत रूप में तेज प्रतीत होगी:

l = [[]]
for _ in range(n): l.extend(map(list,l))

(लंबाई 2 ** एन की एक सूची का उत्पादन करता है, निश्चित रूप से) यह निर्माण सूची की समझ से दोगुना है, समय के अनुसार, दोनों छोटी और लंबी (एक मिलियन) सूची के लिए।

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

from itertools import starmap
l = list(starmap(list,[()]*(1<<n)))

दिलचस्प है कि निष्पादन का समय बताता है कि यह अंतिम सूची कॉल है जो स्टैरमैप समाधान को धीमा बनाता है, क्योंकि इसका निष्पादन समय लगभग गति के बराबर है:

l = list([] for _ in range(1<<n))

मेरा तीसरा प्रयास तब आया जब मुझे पता चला कि सूची (()) भी एक सूची तैयार करती है, इसलिए मैंने सरलता से कोशिश की:

l = list(map(list, [()]*(1<<n)))

लेकिन यह स्टार्मैप कॉल की तुलना में धीमा था।

निष्कर्ष: गति उन्माद के लिए: सूची समझ का उपयोग करें। केवल कॉल फ़ंक्शन, यदि आपको करना है। बिल्डिंस का इस्तेमाल करें।

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