वन-लाइनर यह जांचने के लिए कि क्या एक पुनरावृत्त कम से कम एक तत्व देता है?


102

वर्तमान में मैं यह कर रहा हूं:

try:
    something = iterator.next()
    # ...
except StopIteration:
    # ...

लेकिन मैं एक अभिव्यक्ति चाहूंगा जिसे मैं एक साधारण ifकथन के अंदर रख सकता हूं । क्या ऐसा कुछ बिल्ट-इन है जिससे यह कोड कम अनाड़ी लगेगा?

any()रिटर्न Falseअगर एक चलने योग्य खाली है, लेकिन यह सभी मदों पर संभावित रूप से पुनरावृति करेगा यदि यह नहीं है। मुझे केवल पहले आइटम की जांच करने की आवश्यकता है।


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


2
उस कोड के साथ एक समस्या यह भी है कि आप इसे किसी फ़ंक्शन में पैकेज नहीं कर सकते, क्योंकि यह पहला तत्व खाएगा। अच्छा प्रश्न।
andrrk

2
मेरे मामले में मुझे तत्व की आवश्यकता नहीं है, मैं सिर्फ यह जानना चाहता हूं कि कम से कम एक तत्व है।
बैस्टियन लेओनार्ड

2
हां! एक ही समाधान खोजने की कोशिश में मेरा वही उपयोग मामला!
डैनियल


जवाबों:


134

anyयदि यह सत्य है तो पहले तत्व से आगे नहीं जाएगा। मामले में पुनरावृत्ति करने वाला कुछ गलत-ईश लिख सकता है any(True for _ in iterator)


ऐसा लगता है कि मेरे लिए काम कर रहा है। आप परीक्षण कर सकते हैं कि कोई भी पहली सफलता पर आसानी से रुक जाता है: दौड़ें any((x > 100 for x in xrange(10000000)))और फिर दौड़ें any((x > 10000000 for x in xrange(100000000)))- दूसरे को अधिक समय लेना चाहिए।
chbrown

1
यह "कम से कम x" के मामले में काम करता हैsum(1 for _ in itertools.islice(iterator, max_len)) >= max_len
डेव बटलर

11
इसी प्रकार यदि आपको यह जाँचने की आवश्यकता है कि क्या इट्रेटर खाली है, तो कोई उपयोग कर सकता है all(False for _ in iterator)यदि जाँचकर्ता खाली है। (यदि रिटर्न खाली है तो सभी सही है, अन्यथा यह तब रुकता है जब यह पहला गलत तत्व देखता है)
केजीर्देववीर

23
इस समाधान के साथ बड़ी समस्या यह है कि यदि आप खाली नहीं हैं, तो आप वास्तव में इट्रेटर से लौटे मूल्य का उपयोग नहीं कर सकते हैं?
केन विलियम्स

42

पायथन 2.6+ में, यदि नाम sentinelएक मूल्य से जुड़ा हुआ है , जो पुनरावृत्त संभवतः उपज नहीं दे सकता है,

if next(iterator, sentinel) is sentinel:
    print('iterator was empty')

यदि आपको इस बात का कोई अंदाजा नहीं है कि संभवतः यह क्या पैदावार दे सकता है, तो अपना स्वयं का प्रहरी (जैसे अपने मॉड्यूल के शीर्ष पर) बनाएं

sentinel = object()

अन्यथा, आप प्रहरी भूमिका में, किसी भी मूल्य का उपयोग कर सकते हैं जिसे आप "जानते हैं" (आवेदन के विचारों के आधार पर) कि यह संभवत: उपज नहीं दे सकता है।


1
अच्छा! मेरे उपयोग के मामले के लिए, if not next(iterator, None):पर्याप्त था क्योंकि मुझे यकीन था कि कोई भी वस्तुओं का हिस्सा नहीं होगा। मुझे सही दिशा बताने के लिए धन्यवाद!
वासिगीक

1
@wababi याद रखें कि notयह किसी भी झूठी वस्तु, जैसे कि खाली सूची, गलत और शून्य के लिए सही है। is not Noneसुरक्षित है, और मेरी राय में स्पष्ट है।
Caagr98

21

यह वास्तव में क्लीनर नहीं है, लेकिन यह इसे दोषरहित रूप से कार्य करने का तरीका दिखाता है:

def has_elements(iter):
  from itertools import tee
  iter, any_check = tee(iter)
  try:
    any_check.next()
    return True, iter
  except StopIteration:
    return False, iter

has_el, iter = has_elements(iter)
if has_el:
  # not empty

यह वास्तव में अजगर नहीं है, और विशेष मामलों के लिए, अगले डिफ़ॉल्ट की तरह शायद बेहतर (लेकिन कम सामान्य) समाधान हैं ।

first = next(iter, None)
if first:
  # Do something

यह सामान्य नहीं है क्योंकि कई पुनरावृत्तियों में कोई भी एक मान्य तत्व नहीं हो सकता है।


यह शायद ऐसा करने का सबसे अच्छा तरीका है। हालांकि, यह जानने में मदद मिलेगी कि ओपी क्या करने की कोशिश कर रहा है? वहाँ शायद एक और अधिक सुंदर समाधान है (यह सब के बाद अजगर है)।
रॉसडिपेन

धन्यवाद, मुझे लगता है कि मैं उपयोग करने जा रहा हूं next()
बैस्टियन लेओनार्ड

1
@ बास्टियन, ठीक है, लेकिन एक उचित प्रहरी के साथ ऐसा करें (मेरा उत्तर देखें)।
एलेक्स मार्टेली

3
इस समाधान में एक विशाल स्मृति रिसाव है। अगर teeकिसी को any_checkकभी आगे बढ़ना है, तो पुनरावृत्तियों को मूल इटरेटर से हर एक तत्व को रखना होगा । यह मूल सूची को केवल एक सूची में परिवर्तित करने से भी बदतर है।
राफेल डाउगर्ड 8

1
@ RafałDowgird यह मूल सूची को केवल सूची में परिवर्तित करने से भी बदतर है। वास्तव में नहीं - अनंत दृश्यों के बारे में सोचें।
पियोट्र डोब्रोगोस्ट

6

आप उपयोग कर सकते हैं:

if zip([None], iterator):
    # ...
else:
    # ...

लेकिन यह कोड रीडर के लिए कुछ भी नहीं है


2
.. (आप [कोई नहीं] के बजाय किसी भी 1-आइटम का उपयोग कर सकते हैं)
mykhal

5

सबसे अच्छा तरीका है कि एक peekableसे है more_itertools

from more_itertools import peekable
iterator = peekable(iterator)
if iterator:
    # Iterator is non-empty.
else:
    # Iterator is empty.

बस अगर आप पुराने पुनरावृत्त करने के लिए refs रखा, खबरदार है कि iterator उन्नत हो जाएगा। आपको तब से नए आकर्षक इटैलर का उपयोग करना होगा। वास्तव में, हालांकि, ज्वलनशील को उस पुराने पुनरावृत्ति को संशोधित करने वाले कोड का एकमात्र हिस्सा होने की उम्मीद है, इसलिए आपको वैसे भी पुराने itter के लिए refs नहीं रखना चाहिए।


3

व्हाट अबाउट:

In [1]: i=iter([])

In [2]: bool(next(i,False))
Out[2]: False

In [3]: i=iter([1])

In [4]: bool(next(i,False))
Out[4]: True

4
दिलचस्प एक! लेकिन क्या होगा अगर अगला () गलत रिटर्न करता है क्योंकि यह वही है जो वास्तव में उपज था?
बैस्टियन लेओनार्ड

@ BastienLéonard एक कक्षा बनाएं class NotSet: pass, तो के लिए जाँचif next(i, NotSet) is NotSet: print("Iterator is empty")
Elijas

-1

__length_hint__ की लंबाई का अनुमान है list(it)- यह निजी विधि है, हालांकि:

x = iter( (1, 2, 3) )
help(x.__length_hint__)
      1 Help on built-in function __length_hint__:
      2 
      3 __length_hint__(...)
      4     Private method returning an estimate of len(list(it)).

4
हर पुनरावृत्त के लिए गारंटी नहीं है। >>> इसे (): ... उपज 1 ... उपज 2 ... उपज 3 ... उपज 3 ... >>> मैं = () >>> i .__ length_hint__ Traceback (सबसे हालिया कॉल अंतिम): फ़ाइल " <stdin> ", पंक्ति 1, में <मॉड्यूल> विशेषता गुण: 'जनरेटर' ऑब्जेक्ट में कोई विशेषता नहीं है ' length_hint '
andrewrk

3
यह शायद इसके लिए कानूनी है कि 0 से एक पुनरावृत्ति करने वाले के लिए वापस लौटना जिसमें शून्य से अधिक प्रविष्टियाँ हैं, क्योंकि यह सिर्फ एक संकेत है।
ग्लेन मेयार्ड

-1

यह एक ओवरकिल इट्रिपर रैपर है जो आम तौर पर यह जांचने की अनुमति देता है कि क्या अगला आइटम है (बूलियन में रूपांतरण के माध्यम से)। बेशक बहुत अक्षम है।

class LookaheadIterator ():

    def __init__(self, iterator):
        self.__iterator = iterator
        try:
            self.__next      = next (iterator)
            self.__have_next = True
        except StopIteration:
            self.__have_next = False

    def __iter__(self):
        return self

    def next (self):
        if self.__have_next:
            result = self.__next
            try:
                self.__next      = next (self.__iterator)
                self.__have_next = True
            except StopIteration:
                self.__have_next = False

            return result

        else:
            raise StopIteration

    def __nonzero__(self):
        return self.__have_next

x = LookaheadIterator (iter ([]))
print bool (x)
print list (x)

x = LookaheadIterator (iter ([1, 2, 3]))
print bool (x)
print list (x)

आउटपुट:

False
[]
True
[1, 2, 3]

-2

थोड़ी देर हो गई, लेकिन ... आप पुनरावृत्ति को एक सूची में बदल सकते हैं और फिर उस सूची के साथ काम कर सकते हैं:

# Create a list of objects but runs out the iterator.
l = [_ for _ in iterator]

# If the list is not empty then the iterator had elements; else it was empty.
if l :
    pass # Use the elements of the list (i.e. from the iterator)
else :
    pass # Iterator was empty, thus list is empty.

4
यह अक्षम है क्योंकि यह पूरी सूची को दर्शाता है। अनंत जनरेटर के लिए काम नहीं करेगा।
24

@becko: सहमत। लेकिन यह मूल प्रश्न में मामला नहीं लगता है।
जेन्स

3
एक और समस्या यह है कि इटरेटर उन वस्तुओं की एक अनंत मात्रा उत्पन्न कर सकता है जो स्मृति अतिप्रवाह में परिणाम कर सकते हैं, और यह तथ्य कि कार्यक्रम अगले बयान तक कभी नहीं पहुंचेगा
विलेम वैन ओन्सेम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.