पायथन पुनरावृत्त से अंतिम आइटम प्राप्त करने का सबसे साफ तरीका


110

पायथन 2.6 में एक पुनरावृत्त से अंतिम वस्तु प्राप्त करने का सबसे अच्छा तरीका क्या है? उदाहरण के लिए, कहो

my_iter = iter(range(5))

कम से कम-कोड / होने का साफ तरीका क्या है 4से my_iter?

मैं यह कर सकता था, लेकिन यह बहुत कुशल नहीं लगता है:

[x for x in my_iter][-1]

4
Iterators मान लेते हैं कि आप तत्वों के माध्यम से पुनरावृति करना चाहते हैं और वास्तव में अंतिम तत्वों तक पहुंच नहीं चाहते हैं। केवल सीमा (5) [- 1] का उपयोग करने से आपको क्या रोकता है?
फ्रैंक

7
@ फ्रेंक - मैंने माना कि वास्तविक पुनरावृत्त अधिक जटिल था और / या आगे दूर और / या मुश्किल से नियंत्रित करने के लिएiter(range(5))
क्रिस लुट्ज़

3
@ फ्रेंक: तथ्य यह है कि यह वास्तव में एक बहुत अधिक जटिल जनरेटर फ़ंक्शन है जो पुनरावृत्ति की आपूर्ति करता है। मैंने सिर्फ इस उदाहरण को बनाया ताकि यह सरल और स्पष्ट हो कि क्या हो रहा था।
पीटर

4
यदि आप एक पुनरावृत्त का अंतिम आइटम चाहते हैं, तो एक बड़ा मौका है कि आप कुछ गलत कर रहे हैं। लेकिन इसका उत्तर यह है कि वास्तव में कोई भी क्लीनर तरीका नहीं है जो पुनरावृति के माध्यम से पुनरावृत्ति करता है। ऐसा इसलिए है क्योंकि पुनरावृत्तियों का आकार नहीं होता है, और वास्तव में, कभी भी समाप्त नहीं हो सकता है, और जैसे कि एक अंतिम आइटम नहीं हो सकता है। (मतलब आपका कोड हमेशा के लिए चलेगा, निश्चित रूप से)। तो सवाल यह है कि आप एक अंतिम आइटम क्यों चाहते हैं?
लेन्नर्ट रेगेब्र

3
@Peter: कृपया अपना प्रश्न अपडेट करें। अपने स्वयं के प्रश्न के लिए टिप्पणियों का एक गुच्छा न जोड़ें। कृपया प्रश्न को अपडेट करें और टिप्पणियों को हटा दें।
एस.लॉट

जवाबों:


100
item = defaultvalue
for item in my_iter:
    pass

4
क्यों प्लेसहोल्डर "चूक"? क्यों नहीं None? यह ठीक उसी प्रकार है Noneजैसा कि है। क्या आप सुझाव दे रहे हैं कि कुछ फ़ंक्शन-विशिष्ट डिफ़ॉल्ट मान भी सही हो सकते हैं? यदि इट्रेटर वास्तव में पुनरावृति नहीं करता है, तो कुछ भ्रामक फ़ंक्शन-विशिष्ट डिफ़ॉल्ट की तुलना में एक आउट-ऑफ-बैंड मान अधिक सार्थक है।
11:26

46
डिफ़ॉल्टता मेरे उदाहरण के लिए एक प्लेसहोल्डर है। यदि आप Noneडिफ़ॉल्ट मान के रूप में उपयोग करना चाहते हैं , तो यह आपकी पसंद है। कोई भी हमेशा सबसे समझदार डिफ़ॉल्ट नहीं है, और बैंड से बाहर भी नहीं हो सकता है। व्यक्तिगत रूप से मैं 'डिफॉल्टवे = ऑब्जेक्ट ()' का उपयोग यह सुनिश्चित करने के लिए करता हूं कि यह वास्तव में अद्वितीय मूल्य है। मैं केवल यह संकेत दे रहा हूं कि डिफ़ॉल्ट का विकल्प इस उदाहरण के दायरे से बाहर है।
थॉमस वाउटर्स 11

28
@ एस.लॉट: शायद यह एक खाली पुनरावृत्त और एक पुनरावृत्ति के बीच अंतर को भेदने के लिए उपयोगी है, जिसका Noneअंतिम मूल्य है
जॉन ला रोय

8
सभी निर्मित कंटेनर प्रकार के सभी पुनरावृत्तियों में एक डिज़ाइन त्रुटि है? पहली बार मैंने इसके बारे में सुना है :)
थॉमस वाउटर्स

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

68

dequeआकार 1 का उपयोग करें ।

from collections import deque

#aa is an interator
aa = iter('apple')

dd = deque(aa, maxlen=1)
last_element = dd.pop()

6
यह वास्तव में एक लंबे अनुक्रम को समाप्त करने का सबसे तेज़ तरीका है, हालांकि केवल लूप के लिए तेजी से फिसलन है।
स्वेन मार्नाच

11
तकनीकी रूप से सही होने के लिए +1, लेकिन पाठकों के पास सामान्य रूप से अजगर होना चाहिए, "क्या आपको वास्तव में इसे अनुकूलित करने की आवश्यकता है?", "यह कम स्पष्ट है, जो कि पायथोनिक नहीं है", और "तेज गति कार्यान्वयन पर निर्भर करती है, जो बदल सकता है।"
लेवेज

1
इसके अलावा, यह एक स्मृति-हॉग है
इलको होगेंडोर्न

6
@EelcoHoogendoorn क्यों यह एक मेमोरी-हॉग है, यहां तक ​​कि 1 के अधिकतम के साथ?
क्रिस वेसलिंग

1
अब तक प्रस्तुत सभी समाधानों में से, मुझे यह सबसे तेज और सबसे अधिक स्मृति वाला लगता है
मार्कस स्ट्रॉस

66

यदि आप पायथन 3.x का उपयोग कर रहे हैं:

*_, last = iterator # for a better understanding check PEP 448
print(last)

यदि आप अजगर 2.7 का उपयोग कर रहे हैं:

last = next(iterator)
for last in iterator:
    continue
print last


पक्षीय लेख:

आमतौर पर, ऊपर प्रस्तुत समाधान वह है जो आपको नियमित मामलों के लिए आवश्यक है, लेकिन यदि आप बड़ी मात्रा में डेटा के साथ काम कर रहे हैं, तो dequeआकार 1 का उपयोग करना अधिक कुशल है । ( स्रोत )

from collections import deque

#aa is an interator
aa = iter('apple')

dd = deque(aa, maxlen=1)
last_element = dd.pop()

1
@virtualxtc: अंडरस्कोर सिर्फ एक पहचानकर्ता है। सामने वाला तारा कहता है "सूची का विस्तार करें"। अधिक पठनीय होगा *lst, last = some_iterable
पेप

4
@virtualxtc nope _python में विशेष चर है और इसका उपयोग अंतिम मूल्य को संग्रहीत करने के लिए किया जाता है या यह कहें कि मुझे मूल्य की परवाह नहीं है इसलिए इसे साफ किया जा सकता है।
धियातन

1
वह पायथन 3 समाधान मेमोरी-कुशल नहीं है।
मार्कस स्ट्रॉस

3
@DhiaTN हां, आप बिल्कुल सही हैं। दरअसल, मुझे पाइथन 3 मुहावरा बहुत पसंद आया है। मैं सिर्फ यह स्पष्ट करना चाहता था, कि यह "बड़े डेटा" के लिए काम नहीं करता है। मैं उसके लिए collection.deque का उपयोग करता हूं, जो तेज और मेमोरी कुशल होता है (मार्टिन 23487234 से समाधान देखें)।
मार्कस स्ट्रॉस

1
यह py3.5 + उदाहरण PEP 448 में होना चाहिए। अद्भुत।
एलियाडल

33

__reversed__अगर यह उपलब्ध है तो संभवतः उपयोग करने लायक

if hasattr(my_iter,'__reversed__'):
    last = next(reversed(my_iter))
else:
    for last in my_iter:
        pass

27

की तरह सरल:

max(enumerate(the_iter))[1]

8
ओह, यह चतुर है। सबसे कुशल या पठनीय नहीं, लेकिन चतुर।
टाइमगैब

6
तो बस ज़ोर से सोच रहे हैं ... यह काम करता है क्योंकि जैसे enumerateरिटर्न (index, value): (0, val0), (1, val1), (2, val2)... और तब डिफ़ॉल्ट रूप से maxजब टुपल्स की एक सूची दी जाती है, केवल टुपल के पहले मूल्य के खिलाफ तुलना करता है, जब तक कि दो पहले मान समान नहीं होते हैं, जो वे यहां कभी नहीं हैं क्योंकि वे सूचकांकों का प्रतिनिधित्व करते हैं। फिर अनुगामी सबस्क्रिप्ट इसलिए है क्योंकि अधिकतम संपूर्ण (idx, मान) tuple लौटाता है जबकि हम केवल इसमें रुचि रखते हैं value। दिलचस्प विचार।
टेलर एड्मिस्टन

21

यह मेमने के कारण लूप के लिए खाली होने की तुलना में तेज होने की संभावना नहीं है, लेकिन शायद यह किसी और को एक विचार देगा

reduce(lambda x,y:y,my_iter)

यदि पुनरावृति खाली है, तो एक टाइपर्रोज़ उठाया जाता है


IMHO, यह एक सबसे प्रत्यक्ष है, वैचारिक रूप से। TypeErrorखाली चलने योग्य को बढ़ाने के बजाय , आप प्रारंभिक मान के माध्यम से डिफ़ॉल्ट मान की आपूर्ति कर सकते हैं reduce(), जैसे last = lambda iterable, default=None: reduce(lambda _, x: x, iterable, default)
इग्नहा

9

यह वहाँ है

list( the_iter )[-1]

यदि पुनरावृत्ति की लंबाई वास्तव में महाकाव्य है - इतनी लंबी है कि सूची को भौतिक रूप से समाप्त करने से स्मृति समाप्त हो जाएगी - तो आपको वास्तव में डिजाइन को पुनर्विचार करने की आवश्यकता है।


1
यह सबसे सीधा उपाय है।
laike9m

2
एक टपल का उपयोग करने के लिए हल्का बेहतर है।
क्रिस्टोफर स्मिथ

9
आखिरी वाक्य से दृढ़ता से असहमत हैं। बहुत बड़े डेटासेट्स के साथ काम करना (जो कि मेमोरी सीमा से अधिक हो सकता है यदि एक ही बार में लोड किया गया है) एक सूची के बजाय एक पुनरावृत्ति का उपयोग करने का मुख्य कारण है।
पॉल

@Paul: कुछ फ़ंक्शन केवल एक पुनरावृत्ती लौटाते हैं। यह उस मामले में (गैर-महाकाव्य सूचियों के लिए) एक छोटा और सुंदर पठनीय तरीका है।
सर्व-इन

यह कम से कम कुशल तरीका है जो बुरी बुरी आदत से बचना चाहिए। अनुक्रम का अधिकतम तत्व प्राप्त करने के लिए एक अन्य प्रकार सॉर्ट (अनुक्रम) [- 1] का उपयोग करना है। यदि आप सॉफ्टवेयर इंजीनियर बनना पसंद करते हैं तो कृपया इन बीमार पितरों का उपयोग न करें।
मक्सिम गानेंको

5

मै इस्तेमाल करूंगा reversed , सिवाय इसके कि यह केवल पुनरावृत्तियों के बजाय अनुक्रम लेता है, जो मनमाना लगता है।

किसी भी तरह से आप इसे करते हैं, आपको पूरे पुनरावृत्ति से चलना होगा। अधिकतम दक्षता पर, यदि आपको पुन: पुनरावृत्ति की आवश्यकता नहीं है, तो आप सभी मानों को मिटा सकते हैं:

for last in my_iter:
    pass
# last is now the last item

मुझे लगता है कि यह एक उप-इष्टतम समाधान है, हालांकि।


4
उलट () एक पुनरावृत्ति नहीं लेता है, बस अनुक्रम।
थॉमस वाउटर्स 11

3
यह बिल्कुल भी मनमाना नहीं है। सभी आइटम्स को मेमोरी में रखते हुए, इट्रेटर को रिवर्स करने का एकमात्र तरीका अंत तक चलना है। इससे पहले कि आप इसे उल्टा कर सकें, मैं, ई, आपको पहले एक सीक्वेंस बनाने की जरूरत है। कौन सा पाठ्यक्रम पहली बार में पुनरावृत्त के उद्देश्य को हरा देता है, और इसका मतलब यह भी होगा कि आप अचानक बिना किसी स्पष्ट कारण के बहुत सारी मेमोरी का उपयोग करते हैं। तो यह वास्तव में, मनमाना के विपरीत है। :)
लेनार्ट रेगेब्रो

@ लेन्नर्ट - जब मैंने मनमानी की, तो मेरा मतलब था कि मुझे गुस्सा आ रहा है। मैं इस समय सुबह के समय कुछ घंटों के कारण अपने भाषा कौशल पर ध्यान केंद्रित कर रहा हूं।
क्रिस लुत्ज़

3
काफी उचित। यद्यपि IMO यह अधिक कष्टप्रद होगा यदि यह पुनरावृत्तियों को स्वीकार नहीं करता है, क्योंकि इसका लगभग कोई भी उपयोग एक बुरा विचार (tm) होगा। :)
लेन्आर्ट रेगेब्र

3

Toolz पुस्तकालय एक अच्छा समाधान प्रदान करता है:

from toolz.itertoolz import last
last(values)

लेकिन केवल इस मामले में इसका उपयोग करने के लिए गैर-कोर निर्भरता को जोड़ना इसके लायक नहीं हो सकता है।


1

इस कोड को कुछ इसी तरह देखें:

http://excamera.com/sphinx/article-islast.html

आप अंतिम आइटम को लेने के लिए इसका उपयोग कर सकते हैं:

[(last, e) for (last, e) in islast(the_iter) if last]

1
कृपया islastअपने उत्तर के लिए कोड शामिल करें ( meta.stackexchange.com/questions/8231/… देखें )।
क्रिस्टियन सियुपिटु

0

मैं सिर्फ उपयोग करूंगा next(reversed(myiter))


8
TypeError: तर्क को उलटा करना () एक अनुक्रम होना चाहिए
Labo

0

प्रश्न एक इट्रेटर के अंतिम तत्व को प्राप्त करने के बारे में है, लेकिन अगर आपका इटेरेटर किसी अनुक्रम में शर्तों को लागू करके बनाया जाता है, तो उलटा अनुक्रम के "पहले" को खोजने के लिए इसका उपयोग किया जा सकता है, केवल आवश्यक तत्वों को देखकर, आवेदन करके अनुक्रम के विपरीत।

एक आकस्मिक उदाहरण,

>>> seq = list(range(10))
>>> last_even = next(_ for _ in reversed(seq) if _ % 2 == 0)
>>> last_even
8

0

वैकल्पिक रूप से अनंत पुनरावृत्तियों के लिए आप उपयोग कर सकते हैं:

from itertools import islice 
last = list(islice(iterator(), 1000))[-1] # where 1000 is number of samples 

मैंने सोचा था कि यह धीमी होगी, dequeलेकिन यह उतनी ही तेज है और यह वास्तव में तेज है तो लूप विधि के लिए (किसी तरह)


-6

प्रश्न गलत है और केवल एक उत्तर के लिए नेतृत्व कर सकता है जो जटिल और अक्षम है। पुनरावृति प्राप्त करने के लिए, आप निश्चित रूप से उस चीज से शुरू करते हैं जो कि चलने योग्य है, जो ज्यादातर मामलों में अंतिम तत्व तक पहुंचने का एक अधिक प्रत्यक्ष तरीका प्रदान करता है।

एक बार जब आप एक पुनरावृत्ति से एक पुनरावृत्ति बनाते हैं, तो आप तत्वों के माध्यम से जाने में फंस जाते हैं, क्योंकि यह एकमात्र चीज है जो एक पुनरावृत्ति प्रदान करता है।

तो, सबसे कुशल और स्पष्ट तरीका यह है कि पहली बार में इटरेटर का निर्माण न किया जाए, लेकिन इटेरेबल की मूल पहुंच विधियों का उपयोग किया जाए।


5
तो आपको फ़ाइल की अंतिम पंक्ति कैसे मिलेगी?
ब्राइस एम। डेम्पसे

@ BriceM.Dempsey सबसे अच्छा तरीका पूरी (शायद विशाल) फ़ाइल के माध्यम से पुनरावृत्ति नहीं है, लेकिन फ़ाइल आकार माइनस 100 पर जाकर, अंतिम 100 बाइट्स पढ़ें, उनमें एक नई रेखा के लिए स्कैन करें, अगर कोई नहीं है, तो जाएं एक और 100 बाइट्स इत्यादि वापस करें, आप अपने परिदृश्य के आधार पर अपने स्टेप-बैक साइज़ को भी बढ़ा सकते हैं। एक गज़िलियन लाइनों को पढ़ना निश्चित रूप से एक गैर-इष्टतम समाधान है।
अल्फ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.