2009-07-02 29 views
52

लोग। मैं किसी समस्या का सबसे सुंदर समाधान खोजने की कोशिश कर रहा हूं और सोच रहा हूं कि क्या पाइथन में कुछ भी है जो मैं करने की कोशिश कर रहा हूं।पायथन सूची की समझ; सूचियों की सूची को संपीड़ित करना?

मैं यह कर रहा हूं यह है। मेरे पास एक सूची है, A, और मेरे पास एक कार्य f है जो एक आइटम लेता है और एक सूची देता है। मैं A में सबकुछ बदलने के लिए सूची समझ का उपयोग कर सकता हूं;

[f(a) for a in A] 

लेकिन इस सूचियों की एक सूची प्रदान;

[a1,a2,a3] => [[b11,b12],[b21,b22],[b31,b32]] 

जो मैं वास्तव में चाहता हूं वह फ़्लैटेड सूची प्राप्त करना है;

[b11,b12,b21,b22,b31,b32] 

अब, अन्य भाषाओं में यह है; इसे परंपरागत रूप से कार्यात्मक प्रोग्रामिंग भाषाओं में flatmap कहा जाता है, और .Net इसे SelectMany कहते हैं। क्या पाइथन के समान कुछ है? क्या सूची में फ़ंक्शन को मैप करने और परिणाम को फ़्लैट करने का कोई साफ तरीका है?

वास्तविक समस्या जिसे मैं हल करने की कोशिश कर रहा हूं वह यह है; निर्देशिकाओं की एक सूची से शुरू, सभी उपनिर्देशिका खोजें। इसलिए;

import os 
dirs = ["c:\\usr", "c:\\temp"] 
subs = [os.listdir(d) for d in dirs] 
print subs 

currentliy मुझे एक सूची के- सूचियों देता है, लेकिन मैं वास्तव में एक सूची चाहते हैं।

उत्तर

74

आप एक सूची समझ में पुनरावृत्तियों नेस्ट है कर सकते हैं:

[filename for path in dirs for filename in os.listdir(path)] 
+25

हालांकि चालाक, समझना मुश्किल है और बहुत पठनीय नहीं है। –

+1

वास्तव में पूछे गए प्रश्न का उत्तर नहीं देता है। पहली जगह में समस्या का सामना नहीं करने के लिए यह एक कामकाज है। क्या होगा यदि आपके पास पहले से ही सूचियों की एक सूची है। उदाहरण के लिए, यदि सूचियों की आपकी सूची मल्टीप्रोसेसिंग मॉड्यूल के मानचित्र फ़ंक्शन का परिणाम है तो क्या होगा? शायद itertools समाधान या कम समाधान सबसे अच्छा है। – Dave31415

+8

डेव31415: '[सूची में आइटम के लिए सूची सूची में सूची के लिए आइटम]' – rampion

3

आप itertools.chain(), इस तरह की कोशिश कर सकते:

import itertools 
import os 
dirs = ["c:\\usr", "c:\\temp"] 
subs = list(itertools.chain(*[os.listdir(d) for d in dirs])) 
print subs 

itertools.chain() पुनरावर्तक, इसलिए list() को गुजर देता है।

5
subs = [] 
map(subs.extend, (os.listdir(d) for d in dirs)) 

(लेकिन चींटियों का जवाब बेहतर है; उसके लिए +1)

+0

का उपयोग को कम करने (या योग है, जो आपको कई पात्रों और एक आयात ;-) के लिए यह सिर्फ गलत है बचाता है - आप बेकार करने के लिए पुरानी सूचियां दूर घालना रखना प्रत्येक डी के लिए एक नया बनाओ। @ एंट्स का सही जवाब है (इसे स्वीकार करने के लिए @ स्टेव का स्मार्ट!)। –

+0

@Alex: अच्छा बिंदु। फिक्स्ड। – RichieHindle

+0

आप सामान्य रूप से यह नहीं कह सकते कि यह एक खराब समाधान है। यह इस बात पर निर्भर करता है कि प्रदर्शन भी एक मुद्दा है या नहीं। ऑप्टिमाइज़ करने का कोई कारण होने तक सरल बेहतर होता है। यही कारण है कि कई समस्याओं के लिए कम करने की विधि सबसे अच्छी हो सकती है। उदाहरण के लिए आपके पास धीमा कार्य है जो कुछ सौ वस्तुओं की सूची बनाता है।आप मल्टीप्रोसेसिंग 'मैप' फ़ंक्शन का उपयोग करके इसे तेज करना चाहते हैं। तो आप 4 प्रक्रियाएं बनाते हैं और उन्हें फ्लैट मानचित्र में कम करने का उपयोग करते हैं। इस मामले में कम करने का कार्य ठीक और बहुत पठनीय है। उस ने कहा, यह अच्छा है कि आप इंगित करते हैं कि यह सबोपेटिम क्यों हो सकता है। लेकिन यह हमेशा उपमहाद्वीप नहीं है। – Dave31415

37

आप में itertools' recipes:

def flatten(listOfLists): 
    return list(chain.from_iterable(listOfLists)) 

(नोट एक अच्छा जवाब पा सकते हैं: अजगर 2 की आवश्यकता है।6 +)

+0

उसी दृष्टिकोण का उपयोग फ्लैटमैप को परिभाषित करने के लिए किया जा सकता है, जैसा कि [इस उत्तर] द्वारा प्रस्तावित किया गया है (https://stackoverflow.com/a/20037408/1048186) और यह [बाहरी ब्लॉग पोस्ट] (http://naiquevin.github.io /a-look-at-some-of-pythons-useful-itertools.html) –

3

गूगल मुझे अगले समाधान लाया:

def flatten(l): 
    if isinstance(l,list): 
     return sum(map(flatten,l)) 
    else: 
     return l 
+2

थोड़ा बेहतर होगा यदि यह जेनरेटर अभिव्यक्तियों को भी संभाला जाए, और यदि आप इसे समझाने के तरीके को समझाते हैं तो बहुत बेहतर होगा ... – ephemient

14

तुम बस सीधा कर सकता है:

subs = [] 
for d in dirs: 
    subs.extend(os.listdir(d)) 
+0

हाँ, यह ठीक है (हालांकि @ एंट्स के रूप में काफी अच्छा नहीं है) तो मैं हूं इसे अपनी सादगी का सम्मान करने के लिए एक +1 दे रहा है! –

10

आप सामान्य जोड़ ऑपरेटर का उपयोग कर सूचियों को जोड़ सकते हैं:

>>> [1, 2] + [3, 4] 
[1, 2, 3, 4] 

में निर्मित समारोह sum एक क्रम में संख्या जोड़ देगा और वैकल्पिक रूप से एक विशिष्ट मूल्य से शुरू कर सकते हैं:

>>> sum([[1, 2], [3, 4]], []) 
[1, 2, 3, 4] 
:

>>> sum(xrange(10), 100) 
145 

सूचियों की एक सूची समतल ऊपर कम्बाइन

अब आप अपने flatmap:

>>> def flatmap(f, seq): 
... return sum([f(s) for s in seq], []) 
... 
>>> flatmap(range, [1,2,3]) 
[0, 0, 1, 0, 1, 2] 
0 को परिभाषित कर सकते हैं

संपादित करें: मैंने another answer के लिए टिप्पणियों में आलोचना देखी और मुझे लगता है कि यह सही है कि पाइथन अनिवार्य रूप से निर्माण और कचरा इस समाधान के साथ कई छोटी सूचियों को एकत्रित करेगा। तो सबसे अच्छी बात इसके बारे में कहा जा सकता है, यह है कि यह बहुत ही सरल और संक्षिप्त है अगर आप :-)

+0

उत्कृष्ट उत्तर – Phil

45
>>> listOfLists = [[1, 2],[3, 4, 5], [6]] 
>>> reduce(list.__add__, listOfLists) 
[1, 2, 3, 4, 5, 6] 

कार्यात्मक प्रोग्रामिंग करने के लिए इस्तेमाल कर रहे हैं मेरा अनुमान है कि itertools समाधान इस तुलना में अधिक कुशल है, लेकिन यह बहुत ही पाइथोनिक महसूस करता है और केवल एक सूची ऑपरेशन के लिए लाइब्रेरी आयात करने से बचाता है।

+3

यह निश्चित रूप से सबसे अच्छा समाधान है। –

7
import itertools 
x=[['b11','b12'],['b21','b22'],['b31']] 
y=list(itertools.chain(*x)) 
print y 

itertools python2.3 से काम करेंगे और अधिक से अधिक

14

सवाल flatmap का प्रस्ताव रखा। कुछ कार्यान्वयन प्रस्तावित हैं लेकिन वे अनावश्यक सूची मध्यवर्ती सूचियां बना सकते हैं। यहां एक कार्यान्वयन है जो इटरेटर पर आधारित है।

def flatmap(func, *iterable): 
    return itertools.chain.from_iterable(map(func, *iterable)) 

In [148]: list(flatmap(os.listdir, ['c:/mfg','c:/Intel'])) 
Out[148]: ['SPEC.pdf', 'W7ADD64EN006.cdr', 'W7ADD64EN006.pdf', 'ExtremeGraphics', 'Logs'] 

पायथन 2.x में, map के स्थान पर itertools.map का उपयोग करें।

0
If listA=[list1,list2,list3] 
flattened_list=reduce(lambda x,y:x+y,listA) 

यह करेगा।

+0

यह बहुत ही अक्षम समाधान है यदि उपन्यास बड़े हैं। दो सूचियों के बीच '+' ऑपरेटर ओ (एन + एम) है –

1
def flat_list(arr): 
    send_back = [] 
    for i in arr: 
     if type(i) == list: 
      send_back += flat_list(i) 
     else: 
      send_back.append(i) 
    return send_back 
1

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

from pyxtension.streams import stream 
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7) 
संबंधित मुद्दे