सूची बोध में दोहरापन


226

पायथन में आप एक सूची समझ में कई पुनरावृत्तियों को रख सकते हैं, जैसे

[(x,y) for x in a for y in b]

कुछ उपयुक्त दृश्यों के लिए ए और बी। मैं पायथन की सूची समझ के नेस्टेड लूप शब्दार्थ से अवगत हूं।

मेरा सवाल है: क्या एक पुनरावृत्ति दूसरे में संदर्भित कर सकता है? दूसरे शब्दों में: क्या मेरे पास ऐसा कुछ हो सकता है:

[x for x in a for a in b]

जहां बाहरी लूप का वर्तमान मूल्य आंतरिक का पुनरावृत्ति है?

एक उदाहरण के रूप में, अगर मेरे पास एक नेस्टेड सूची है:

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

इस परिणाम को प्राप्त करने के लिए सूची समझ अभिव्यक्ति क्या होगी:

[1,2,3,4]

?? (कृपया केवल उत्तर समझने की सूची बनाएं, क्योंकि यह वही है जो मैं जानना चाहता हूं)।

जवाबों:


178

अपने सुझाव के साथ अपने प्रश्न का उत्तर देने के लिए:

>>> [x for b in a for x in b] # Works fine

जब आप सूची समझने के लिए उत्तर देते हैं, तो मुझे उत्कृष्ट इटेरूलसैचिन () को इंगित करने दें:

>>> from itertools import chain
>>> list(chain.from_iterable(a))
>>> list(chain(*a)) # If you're using python < 2.6

10
[x for b in a for x in b]यह हमेशा अजगर के बारे में हो सकता है। यह वाक्य-विन्यास इतना पीछे है। x for x in yहमेशा का सामान्य रूप इसके बाद का चर होता है, अभिव्यक्ति के लिए बाईं ओर फ़ीड होता है। जैसे ही आप एक डबल कॉम्प्रिहेंशन करते हैं, आपका सबसे हाल ही में चलने वाला वेरिएबल अचानक "दूर" हो जाता है। यह अजीब है, और सभी को एक स्वाभाविक रूप से नहीं पढ़ता
क्रंचर

169

मुझे आशा है कि यह किसी और की मदद करता है क्योंकि a,b,x,yमेरे लिए बहुत मायने नहीं रखता है ! मान लीजिए कि आपके पास वाक्यों से भरा एक पाठ है और आप शब्दों की एक सरणी चाहते हैं।

# Without list comprehension
list_of_words = []
for sentence in text:
    for word in sentence:
       list_of_words.append(word)
return list_of_words

मुझे क्षैतिज रूप से स्ट्रेचिंग कोड के रूप में सूची समझ के बारे में सोचना पसंद है।

इसे तोड़ने की कोशिश करें:

# List Comprehension 
[word for sentence in text for word in sentence]

उदाहरण:

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> [word for sentence in text for word in sentence]
['Hi', 'Steve!', "What's", 'up?']

यह जनरेटर के लिए भी काम करता है

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> gen = (word for sentence in text for word in sentence)
>>> for word in gen: print(word)
Hi
Steve!
What's
up?

8
"कंप्यूटर विज्ञान में केवल दो कठिन समस्याएं हैं: कैश अमान्यकरण और चीजों का नामकरण।" - फिल कार्लटन
सीज़र

यह एक महान जवाब है क्योंकि यह पूरी समस्या को कम सार बनाता है! धन्यवाद!
ए। बेलसियस

मैं सोच रहा था, क्या आप एक सूची समझ में तीन अमूर्त स्तरों के साथ भी ऐसा कर सकते हैं? जैसे पाठ में अध्याय, वाक्य में अध्याय और वाक्य में वाक्य?
कप्तान फोगेट्टी

123

Gee, मुझे लगता है कि मुझे awser मिला: मैं इस बात का ध्यान नहीं रख रहा था कि कौन सा लूप आंतरिक है और कौन सा बाहरी है। सूची की समझ इस प्रकार होनी चाहिए:

[x for b in a for x in b]

वांछित परिणाम प्राप्त करने के लिए, और हां, एक मौजूदा मूल्य अगले लूप के लिए पुनरावृत्ति हो सकता है।


67
सूची बोध वाक्यविन्यास पायथन के चमकदार बिंदुओं में से एक नहीं है।
ग्लेन मेनार्ड

2
@ ग्लेन हाँ, यह आसानी से सरल अभिव्यक्तियों से अधिक के लिए दृढ़ हो जाता है।
थॉमस जूल

1
Ew। मुझे यकीन नहीं है कि यह सूची बोध के लिए "सामान्य" उपयोग है, लेकिन यह बहुत दुर्भाग्यपूर्ण है कि पायनियर में पायनियर बहुत बुरा है।
मैट जॉइनर

14
यह बहुत साफ दिखता है यदि आप प्रत्येक 'के लिए' से पहले नई सुर्खियों में आते हैं।
निक गारवे

16
वाह, यह पूरी तरह से उलट है जो मेरे सिर में समझ में आता है।
obskyr

51

पुनरावृत्तियों के आदेश काउंटर-सहज ज्ञान युक्त लग सकते हैं।

उदाहरण के लिए: [str(x) for i in range(3) for x in foo(i)]

चलो इसे विघटित करें:

def foo(i):
    return i, i + 0.5

[str(x)
    for i in range(3)
        for x in foo(i)
]

# is same as
for i in range(3):
    for x in foo(i):
        yield str(x)

4
क्या एक आंख खोलने वाला !!
नेहेम

मेरी समझ यह है कि इसका कारण यह है कि "सूचीबद्ध पहला पुनरावृति सबसे ऊपरी पुनरावृत्ति है जिसे टाइप किया जाएगा यदि समझ को छोरों के लिए नेस्टेड के रूप में लिखा गया था"। इसका कारण यह है कि काउंटरपेंटिव है कि OUTER लूप (सबसे ऊपर अगर नेस्ट-लूप्स के रूप में लिखा जाता है) ब्रैकेटेड लिस्ट / इनसाइड (comprehensioneded ऑब्जेक्ट) के INSIDE में दिखाई देता है। इसके विपरीत, INNER लूप (अंतरतम जब लूप के लिए नेस्टेड के रूप में लिखा जाता है) ठीक एक समझ में सबसे सही लूप है, और इस तरह से समझ के OUTSIDE में प्रकट होता है।
ज़ैक सीगल

संक्षेप में लिखा हमारे पास [(output in loop 2) (loop 1) (loop 2)]साथ (loop 1) = for i in range(3)और (loop 2) = for x in foo(i):और (output in loop 2) = str(x)
कासवेद

20

थॉमसएच ने पहले ही एक अच्छा जवाब जोड़ दिया है, लेकिन मैं दिखाना चाहता हूं कि क्या होता है:

>>> a = [[1, 2], [3, 4]]
>>> [x for x in b for b in a]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined

>>> [x for b in a for x in b]
[1, 2, 3, 4]
>>> [x for x in b for b in a]
[3, 3, 4, 4]

मुझे लगता है कि पायथन सूची को बाएं से दाएं की ओर समझ रहा है। इसका मतलब है, पहला forलूप जो होता है उसे पहले निष्पादित किया जाएगा।

इसकी दूसरी "समस्या" यह है कि bसूची की समझ से बाहर "लीक" हो जाता है। पहली सफल सूची समझ के बाद b == [3, 4]


3
दिलचस्प बिंदु। मुझे इस पर आश्चर्य हुआ:x = 'hello'; [x for x in xrange(1,5)]; print x # x is now 4
17:18 बजे ग्रिन

2
पायथन 3 में यह रिसाव तय किया गया था: stackoverflow.com/questions/4198906/…
डेनिल्सन सिया मिया

10

यदि आप बहुआयामी सरणी रखना चाहते हैं, तो किसी को सरणी कोष्ठक में घोंसला बनाना चाहिए। नीचे देखें उदाहरण जहां हर तत्व में एक जोड़ा जाता है।

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

>>> [[col +1 for col in row] for row in a]
[[2, 3], [4, 5]]

>>> [col +1 for row in a for col in row]
[2, 3, 4, 5]

8

यह मेमोरी टेक्निक मुझे बहुत मदद करता है:

[ <RETURNED_VALUE> <OUTER_LOOP1> <INNER_LOOP2> <INNER_LOOP3> ... <OPTIONAL_IF> ]

और अब आप R eturn + O uter-loop के बारे में केवल R ight O rder के रूप में सोच सकते हैं

ऊपर जानते हुए, 3 छोरों के लिए भी व्यापक सूची में आदेश आसान लगता है:


c=[111, 222, 333]
b=[11, 22, 33]
a=[1, 2, 3]

print(
  [
    (i, j, k)                            # <RETURNED_VALUE> 
    for i in a for j in b for k in c     # in order: loop1, loop2, loop3
    if i < 2 and j < 20 and k < 200      # <OPTIONAL_IF>
  ]
)
[(1, 11, 111)]

क्योंकि ऊपर सिर्फ एक है:

for i in a:                         # outer loop1 GOES SECOND
  for j in b:                       # inner loop2 GOES THIRD
    for k in c:                     # inner loop3 GOES FOURTH
      if i < 2 and j < 20 and k < 200:
        print((i, j, k))            # returned value GOES FIRST

एक नेस्टेड सूची / संरचना की पुनरावृत्ति के लिए, टेक्निक एक ही है: aप्रश्न से:

a = [[1,2],[3,4]]
[i2    for i1 in a      for i2 in i1]
which return [1, 2, 3, 4]

एक दूसरे नेस्टेड स्तर के लिए

a = [[[1, 2], [3, 4]], [[5, 6], [7, 8, 9]], [[10]]]
[i3    for i1 in a      for i2 in i1     for i3 in i2]
which return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

और इसी तरह


धन्यवाद, लेकिन आप जो वर्णन करते हैं वह वास्तव में एक साधारण मामला है जिसमें शामिल पुनरावृत्तियाँ स्वतंत्र हैं। वास्तव में, आपके उदाहरण में आप किसी भी क्रम में पुनरावृत्तियों का उपयोग कर सकते हैं और समान परिणाम सूची (मॉडुलो ऑर्डरिंग) प्राप्त करेंगे। जिस मामले में मुझे अधिक दिलचस्पी थी, वह नेस्टेड सूचियों के साथ था, जहां एक पुनरावृत्त अगले के चलने योग्य हो जाता है।
थॉमस

@ThomasH: बोल्ड में परिभाषित लूप का क्रम आपकी आवश्यकता के लिए ठीक है। तल पर अपने डेटा को कवर करने के लिए एक उदाहरण और अतिरिक्त नेस्टेड स्तर के साथ एक और उदाहरण जोड़ा।
सोलावोमिर लेनर्ट

5

मुझे लगता है कि यह समझना आसान है

[row[i] for row in a for i in range(len(a))]

result: [1, 2, 3, 4]

3

इसके अतिरिक्त, आप इनपुट सूची के सदस्य के लिए केवल उसी चर का उपयोग कर सकते हैं जो वर्तमान में एक्सेस किया गया है और इस सदस्य के अंदर तत्व के लिए है। हालाँकि, यह इसे और अधिक (सूची) समझ से बाहर कर सकता है।

input = [[1, 2], [3, 4]]
[x for x in input for x in x]

पहले for x in inputमूल्यांकन किया जाता है, इनपुट की एक सदस्य सूची के लिए अग्रणी है, फिर, पायथन दूसरे भाग के माध्यम से चलता है, for x in xजिसके दौरान एक्स-मूल्य को वर्तमान तत्व द्वारा अधिलेखित कर दिया जाता है, फिर वह xपरिभाषित करता है कि हम क्या लौटना चाहते हैं।


1

यह flatten_nlevel फ़ंक्शन एक स्तर पर गुप्त करने के लिए पुनरावर्ती नेस्टेड सूची 1 को कॉल करता है। इसे आज़माएं

def flatten_nlevel(list1, flat_list):
    for sublist in list1:
        if isinstance(sublist, type(list)):        
            flatten_nlevel(sublist, flat_list)
        else:
            flat_list.append(sublist)

list1 = [1,[1,[2,3,[4,6]],4],5]

items = []
flatten_nlevel(list1,items)
print(items)

उत्पादन:

[1, 1, 2, 3, 4, 6, 4, 5]

1
ठीक है, सवाल विशेष रूप से सूची समझ के बारे में था, और सूची सपाट करना केवल एक उदाहरण था। लेकिन मुझे लगता है, अपने सामान्यीकृत सूची के फ्लैटर को खुद को पुनरावर्ती रूप से कॉल करने की आवश्यकता होगी। तो यह शायद अधिक पसंद है flatten_nlevel(sublist, flat_list), है ना ?!
थॉमस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.