2015-09-24 11 views
8

मैं जानना चाहता हूं कि जेनरेट किए गए अनुक्रम में 2 से कम प्रविष्टियां हैं या नहीं।जेनरेट किए गए अनुक्रम को कैसे पता चलेगा एक निश्चित लंबाई

>>> secret = 5 
>>> len(list(sequence())) < 2 
True 

जाहिर है, इस पूरे जनरेटर की खपत:

>>> def sequence(): 
...  for i in xrange(secret): 
...   yield i 

मेरे अक्षम विधि सूची बनाते हैं, और इसकी लंबाई को मापने के लिए है।

मेरे असली मामले में जनरेटर एक बड़े नेटवर्क को पार कर सकता है। मैं पूरे जेनरेटर का उपभोग किए बिना चेक करना चाहता हूं, या बड़ी सूची बनाना चाहता हूं।

एक recipe in the itertools documentation नहीं है:

def take(n, iterable): 
    "Return first n items of the iterable as a list" 
    return list(islice(iterable, n)) 

यह केवल अधिकतम लंबाई n है, जो बेहतर है की एक सूची बनाता है।

तो मैं कह सकते हैं:

>>> len(take(2, sequence()) < 2 

वहाँ एक और भी अधिक pythonic, कुशल यह करने के लिए रास्ता नहीं है?

+0

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

+0

चुपचाप असंबंधित लेकिन सामान्य नियम 'सूची (पुनरावर्तक)' से सावधान रहें, इटरेटर अनंत हो सकते हैं ... –

+1

निश्चित रूप से मुख्य प्रश्न यह है कि - यदि आप लंबे समय तक लंबे समय तक जा रहे हैं, तो यह * आप * बिना * उपभोग करने वाले को कैसे जानते होंगे, या पर्याप्त छोटा? आपका शीर्षक प्रश्न के साथ संघर्ष करने लगता है)? क्या आपके पास कोई अन्य जानकारी है जो आपको यह निर्धारित करने की अनुमति दे सकती है? – jonrsharpe

उत्तर

0

take का उपयोग कर समाधान islice का उपयोग करता है, हम sum उपयोग कर सकते हैं

>>> from itertools import islice 
>>> len(list(islice(sequence(), 2)) 
2 

सूची बनाने से बचने के लिए: एक सूची बनाता है और यह की लंबाई लेता

+०१२३५१६४१०६

>>> timeit('len(list(islice(xrange(1000), 2)))', 'from itertools import islice') 
1.089650974650752 

>>> timeit('sum(1 for _ in islice(xrange(1000), 2))', 'from itertools import islice') 
0.7579448552500647 

इसे रैपिंग:

>>> sum(1 for _ in islice(sequence(), 2) 
2 

इस बार का लगभग 70% लेता है

>>> def at_most(n, elements): 
...  return sum(1 for _ in islice(elements, n + 1)) <= n 

>>> at_most(5, xrange(5)) 
True 

>>> at_most(2, xrange(5)) 
False 
7

पायथन 3.4 के रूप में, जेनरेटर length hint लागू कर सकते हैं। यदि कोई जनरेटर इसे लागू करता है तो इसे object.__length_hint__() method के माध्यम से उजागर किया जाएगा।

आप इसके लिए operator.length_hint() function के साथ परीक्षण कर सकते हैं।

अगर ऐसा है उपलब्ध नहीं, अपने ही एकमात्र विकल्प तत्वों का उपभोग करने के लिए है, और take() नुस्खा के आपके उपयोग करने के लिए सबसे कारगर तरीका है:

from operator import length_hint 
from itertools import chain 

elements = [] 
length = length_hint(gen, None) 
if length is None: 
    elements = list(take(2, gen)) 
    length = len(elements) 
if length >= 2: 
    # raise an error 
# use elements, then gen 
gen = chain(elements, gen) 
+0

बहुत रोचक, धन्यवाद - मैं इस __length_hint __() के आंतरिक कार्यों के बारे में उत्सुक हूं ... :) –

+0

@ReblochonMasque: कई जनरेटर लंबाई की पूर्व-गणना कर सकते हैं या कम से कम अनुमान लगा सकते हैं। यह पूरी तरह से जेनरेटर पर निर्भर करता है, हालांकि। –

+0

मुझे यह नहीं पता था, धन्यवाद। –

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