2010-04-23 7 views
11

मैं एक iterable (upd के पहले n से अधिक आइटम पुनरावृत्ति की एक pythonic रास्ता तलाश कर रहा हूँ से अधिक तेजी से बार-बार दोहराना सूचियों के लिए चीजें छोटी हैं), और जितनी जल्दी हो सके इसे करने के लिए यह काफी महत्वपूर्ण है। इस तरह मैं इसे अब करता हूं:अजगर में एक iterable (नहीं एक सूची) के पहले n आइटम

count = 0 
for item in iterable: 
do_something(item) 
count += 1 
if count >= n: break 

मुझे साफ नहीं लगता है। ऐसा करने का एक और तरीका है:

for item in itertools.islice(iterable, n): 
    do_something(item) 

यह अच्छा लग रहा है, सवाल यह काफी तेजी से कुछ जनरेटर (रों) के साथ उपयोग करने के लिए है? उदाहरण के लिए:

pair_generator = lambda iterable: itertools.izip(*[iter(iterable)]*2) 
for item in itertools.islice(pair_generator(iterable), n): 
so_something(item) 

क्या यह पहली विधि की तुलना में तेज़ी से दौड़ जाएगा? क्या ऐसा करने का कोई आसान तरीका है?

+3

एक ही तरीका है जवाब देने के लिए "काफी तेजी से" यह अपने आप बेंचमार्क है। –

+0

यह भी देखें: http://stackoverflow.com/questions/2688079/how-to-iterate-over-the-first-n-elements-of-a-list – outis

+0

ऐसा क्यों है "इसे जितना तेज़ करना है मुमकिन"? क्या आप इसे यथार्थवादी उपयोग के मामले के लिए pstats परिणामों के साथ औचित्य साबित कर सकते हैं? मुझे संदेह है कि 'islice' के साथ आपका समाधान वास्तव में सर्वोत्तम उचित समाधान प्रदर्शन के अनुसार साबित होगा, लेकिन निश्चित रूप से हम समय के बिना नहीं जानते हैं। –

उत्तर

14

for item in itertools.islice(iterable, n): सबसे स्पष्ट, आसान तरीका है इसे करने के लिए। यह मनमाने ढंग से पुनरावृत्तियों के लिए काम करता है और ओ (एन) है, जैसे किसी भी सोल समाधान होगा।

यह कल्पना की जा सकती है कि एक और समाधान बेहतर प्रदर्शन कर सकता है; हम समय के बिना नहीं पता होगा। मैं समय के साथ परेशान करने की अनुशंसा नहीं करता जबतक कि आप profile अपना कोड न दें और यह कॉल हॉटस्पॉट बनें। जब तक यह एक आंतरिक पाश के भीतर buries नहीं है, यह बहुत संदिग्ध है कि यह होगा। सभी बुराईयो की जड़ समयपूर्व इष्टतमीकरण है।


अगर मैं था वैकल्पिक समाधान के लिए लग रहा है, मैं for count, item in enumerate(iterable): if count > n: break ... और for i in xrange(n): item = next(iterator) ... की तरह लोगों पर विचार करेंगे। मुझे लगता है कि इससे मदद मिलेगी, लेकिन अगर हम वास्तव में चीजों की तुलना करना चाहते हैं तो वे कोशिश करने लायक हैं। अगर मैं ऐसी परिस्थिति में फंस गया था जहां मैंने प्रोफाइल किया और पाया कि यह एक आंतरिक लूप में एक हॉटस्पॉट था (क्या यह वास्तव में आपकी स्थिति है?), मैं islice वैश्विक iterools की विशेषता प्राप्त करने से नाम लुकअप को भी कम करने का प्रयास करूंगा फ़ंक्शन को स्थानीय नाम पर पहले से बाध्य करना।

ये चीजें हैं जो आप साबित करने के बाद ही करते हैं कि वे आपकी सहायता करेंगे। लोग उन्हें कई बार करने की कोशिश करते हैं। यह उनके कार्यक्रमों को तेजी से तेज़ी से बनाने में मदद नहीं करता है; यह सिर्फ अपने कार्यक्रमों को और खराब बनाता है।

+1

उत्तर के लिए बहुत बहुत धन्यवाद, इससे मुझे बहुत मदद मिली! – martinthenext

+0

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

1

सूची में से एक? प्रयास करें

for k in mylist[0:n]: 
    # do stuff with k 

आप भी एक समझ अगर आप

my_new_list = [blah(k) for k in mylist[0:n]] 
+0

हाँ, मुझे मिल गया। गलत शीर्षक, क्षमा करें, मेरा बुरा। – martinthenext

2

की जरूरत का उपयोग कर सकते हैं यह एक सूची है तो आप उपयोग कर सकते हैं टुकड़ा करने की क्रिया है:

list[:n] 
6

itertools सीधे लागू होने पर सबसे तेज़ समाधान होता है।

जाहिर है, की जांच करने के लिए एक ही रास्ता बेंचमार्क है - जैसे, aaa.py

import itertools 

def doit1(iterable, n, do_something=lambda x: None): 
    count = 0 
    for item in iterable: 
    do_something(item) 
    count += 1 
    if count >= n: break 

def doit2(iterable, n, do_something=lambda x: None): 
    for item in itertools.islice(iterable, n): 
     do_something(item) 

pair_generator = lambda iterable: itertools.izip(*[iter(iterable)]*2) 

def dd1(itrbl=range(44)): doit1(itrbl, 23) 
def dd2(itrbl=range(44)): doit2(itrbl, 23) 

में बचाने के लिए और देखें ...:

$ python -mtimeit -s'import aaa' 'aaa.dd1()' 
100000 loops, best of 3: 8.82 usec per loop 
$ python -mtimeit -s'import aaa' 'aaa.dd2()' 
100000 loops, best of 3: 6.33 usec per loop 

इतनी स्पष्ट रूप से, itertools तेजी से यहाँ है - सत्यापित करने के लिए अपने स्वयं के डेटा के साथ बेंचमार्क।

बीटीडब्ल्यू, मुझे timeit कमांड लाइन से अधिक उपयोग करने योग्य लगता है, इसलिए मैं हमेशा इसका उपयोग कैसे करता हूं - फिर यह उस गति के सही "गति का क्रम" चलाता है जिसकी आप विशेष रूप से मापने की कोशिश कर रहे हैं , उन 10, 100, 1000, और इतने पर - यहां, एक माइक्रोसेकंद और अंतर का आधा अंतर करने के लिए, एक सौ हजार लूप सही हैं।

+1

अजीब, यह सिर्फ मेरे cplusplus'ish अंतर्ज्ञान के खिलाफ है जो एक साफ समाधान को एक साफ से धीमी गति से चलाने के लिए है। पाइथन वास्तव में सबसे अच्छी भाषा है। यह माइक ग्राहम की सलाह के लिए समयपूर्व अनुकूलन न करने की सलाह के लिए एक बड़ा जोड़ा है। मुझे लगता है कि सामान्य नियम लिखना है कि क्या चल रहा है, समय चलने के बारे में सोच नहीं। – martinthenext

+1

@ मार्टिन, व्यक्तिगत रूप से, मुझे लगता है कि चलने के समय के बारे में _lot_ (ज्यादातर स्केलेबिलिटी के लिए बड़े-ओ के मामले में) - लेकिन, सामान्य रूप से, अधिकांश पाइथोनिक मुहावरे अक्सर उन लोगों के रूप में होते हैं जिन्हें सबसे अधिक अनुकूल बनाया गया है, क्योंकि वे आमतौर पर हम पाइथन कमेटर्स के बारे में अधिकतर देखभाल करते हैं (हेटिंगर, इटारटोल के लेखक और पायथन के अन्य तेज़ हिस्सों, हाल के वर्षों में उस क्षेत्र में काफी सक्रिय रहे हैं, जैसा कि पिछले वर्षों में पीटर्स था, लेकिन यह एक सुंदर सामान्य है पायथन-कम्युनिटी समुदाय में घटना)। –

2

आप enumerate उपयोग कर सकते हैं मूलतः एक ही पाश आपके पास लिखने के लिए, लेकिन एक और अधिक सरल, pythonic तरह से:

 
for idx, val in enumerate(iterableobj): 
    if idx > n: 
     break 
    do_something(val) 
+0

इस विकल्प पर चर्चा की गई है, एक अच्छा विकल्प की तरह दिखता है, लेकिन मुझे लगता है कि 'islice' बेहतर है क्योंकि इसे लूप बॉडी में किसी भी अतिरिक्त चर की आवश्यकता नहीं होती है, जिससे यह मुझे स्पष्ट दिखता है – martinthenext

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

  • कोई संबंधित समस्या नहीं^_^