2017-02-22 6 views
32

मेरे पास list है और एक और सूची (समझ के माध्यम से) बनाना चाहते हैं। मैं चाहूँगा इस नई सूची, आकार में सीमित करने के लिए किया जा एक शर्त के माध्यम सेसमझ के आकार को सीमित कैसे करें?

निम्नलिखित कोड विफल हो जाएगा:

a = [1, 2, 1, 2, 1, 2] 
b = [i for i in a if i == 1 and len(b) < 3] 

साथ

Traceback (most recent call last): 
    File "compr.py", line 2, in <module> 
    b = [i for i in a if i == 1 and len(b) < 3] 
    File "compr.py", line 2, in <listcomp> 
    b = [i for i in a if i == 1 and len(b) < 3] 
NameError: name 'b' is not defined 

क्योंकि b पर अभी तक परिभाषित नहीं है समय समझ आ गई है।

क्या बिल्ड समय पर नई सूची के आकार को सीमित करने का कोई तरीका है?

नोट: मैं जब एक काउंटर तक पहुँच जाता है उचित break के साथ एक for लूप में समझ को तोड़ सकते थे, लेकिन मैं अगर वहाँ एक व्यवस्था है जिसके एक समझ का उपयोग करता है पता करने के लिए करना चाहते हैं।

उत्तर

52

आप एक जनरेटर अभिव्यक्ति का उपयोग छानने ऐसा करने के लिए, तो islice() उपयोग कर सकते हैं पुनरावृत्तियों की संख्या को सीमित करने के लिए:

from itertools import islice 

filtered = (i for i in a if i == 1) 
b = list(islice(filtered, 3)) 

यह सुनिश्चित करता है कि आप अधिक काम करना नहीं है की तुलना में आप उन 3 तत्वों का उत्पादन करने के लिए है ।

ध्यान दें कि यहां सूची समझ का उपयोग करने में अब कोई बिंदु नहीं है; एक सूची समझ को तोड़ा नहीं जा सकता है, आप अंत में पुनरावृत्त में बंद कर रहे हैं।

+0

'[1/i मैं रेंज में (-5, 5)]' टूट जाता है और अंत तक नहीं चलता है। –

+12

@StefanPochmann: यह एक अपवाद उठाता है, यह * ब्रेक' कथन के समान * नहीं है। अंत में, आपके पास कोई सूची परिणाम नहीं है। –

+0

मुझे यह स्पष्ट नहीं था कि आपका मतलब 'ब्रेक' कथन है, यह शब्द अधिक सामान्य तरीके से समझा जा सकता है। [उदाहरण के लिए] (http://stackoverflow.com/a/38675546/1672429) बहुत समय पहले आपने कहा था "* [' वापसी '] लूप से बाहर तोड़ता है "*। किसी भी मामले में, पुनरावृत्ति अंत तक नहीं जाती है। साथ ही, सूची परिणाम न होने पर भी एक समस्या नहीं होनी चाहिए। 'Reciprocals = [x में x के लिए 1/x] पर विचार करें, मुझे लगता है कि यह उचित कोड है और यदि' a' में शून्य है तो कोई भी 'ZeroDivisionError'' चाहता है और सूची नहीं चाहता है। –

6

@Martijn Pieters पूरी तरह से सही है कि itertools.islice इसे हल करने का सबसे अच्छा तरीका है। हालांकि यदि आपको कोई अतिरिक्त (बाहरी) लाइब्रेरी नहीं है तो आप iteration_utilities का उपयोग कर सकते हैं जो इन itertools और उनके अनुप्रयोगों (और कुछ अतिरिक्त वाले) को बहुत से लपेटता है। यह इस थोड़ा आसान कम से कम अगर आप कार्यात्मक प्रोग्रामिंग की तरह बना सकते हैं,:

>>> from iteration_utilities import Iterable 

>>> Iterable([1, 2, 1, 2, 1, 2]).filter((1).__eq__)[:2].as_list() 
[1, 1] 

>>> (Iterable([1, 2, 1, 2, 1, 2]) 
...   .filter((1).__eq__) # like "if item == 1" 
...   [:2]     # like "islice(iterable, 2)" 
...   .as_list())   # like "list(iterable)" 
[1, 1] 

iteration_utilities.Iterable वर्ग जनरेटर का उपयोग करता है आंतरिक रूप से तो यह केवल प्रक्रिया आवश्यक के रूप में कई आइटम जब तक आप में से किसी को कॉल करेंगे as_* (या get_*) -methods।


अस्वीकरण: मैं the iteration_utilities library के लेखक हूँ।

+1

यह एक बहुत अच्छी लाइब्रेरी है, धन्यवाद (अभी भी कार्यों की भीड़ पर समझ पाने के लिए दस्तावेज़ों को पढ़ना) – WoJ

+1

क्या मैं प्रोजेक्ट के होम पेज पर पहला लिंक बदलने की सलाह दे सकता हूं: http://iteration-utilities.readthedocs.io/ एन/नवीनतम /? – jpmc26

3

आप और itertools.count इस्तेमाल कर सकते हैं itertools.takewhile एक काउंटर उत्पन्न करने के लिए एक जनरेटर से अधिक बार-बार दोहराना को रोकने के लिए जब काउंटर वांछित पूर्णांक (3 इस मामले में) तक पहुँच जाता है:

from itertools import count, takewhile 
c = count() 
b = list(takewhile(lambda x: next(c) < 3, (i for i in a if i == 1))) 

या किसी ऐसे ही विचार एक निर्माण निर्माण जनरेटर को समाप्त करने के लिए StopIteration बढ़ाने के लिए।यही कारण है कि निकटतम आप breaking the list comprehension के अपने मूल विचार करने के लिए मिल जाएगा है, लेकिन मैं सबसे अच्छा अभ्यास के रूप में यह सिफारिश नहीं होगा:

c = count() 
b = list(i if next(c) < 3 else next(iter([])) for i in a if i == 1) 

उदाहरण:

>>> a = [1,2,1,4,1,1,1,1] 

>>> c = count() 
>>> list(takewhile(lambda x: next(c) < 3, (i for i in a if i == 1))) 
[1, 1, 1] 

>>> c = count() 
>>> list(i if next(c) < 3 else next(iter([])) for i in a if i == 1) 
[1, 1, 1] 
+0

क्या अन्य उत्तरों के बारे में इसका क्या फायदा है? – jpmc26

+0

@ jpmc26 मुझे नहीं लगता कि यह इस सटीक उद्देश्य के लिए मार्टिजन के समाधान से बेहतर है, लेकिन यह अधिक सामान्य है क्योंकि जनरेटर को समाप्त करने की स्थितियां कुछ भी हो सकती हैं, केवल एक काउंटर नहीं। इसके अलावा ओपी ने विशेष रूप से एक सूची समझ के बारे में पूछा और यह –

+1

पर्याप्त निकटतम वैध वाक्यविन्यास है। धन्यवाद। चूंकि आपने अन्य उत्तरों के बाद यह अच्छी तरह से पोस्ट किया है, इसलिए आप अपने उत्तर में लचीलापन लाभ के बारे में कुछ काम करना चाहेंगे। – jpmc26

-2

उपयोग की गणना:

b = [n for i,n in enumerate(a) if n==1 and i<3] 
+4

यह बस गलत है। सबसे पहले, यह 'ए' के पहले 3 आइटम को छोड़कर सबकुछ त्याग देगा (प्रश्न' बी 'को सीमित नहीं करना चाहता था) और यह पूरे पुन: प्रयोज्य को संसाधित करेगा। यह तीसरी वस्तु खोजने के बाद नहीं रुक जाएगा। यह उसके बाद सब कुछ छोड़ देता है (हालांकि यह 'n == 1 और i <3') की जांच करेगा। – MSeifert

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