सूचियों की अनियमित सूची को समतल करें


440

हां, मुझे पता है कि इस विषय को पहले ( यहां , यहां , यहां , यहां ) कवर किया गया है , लेकिन जहां तक ​​मुझे पता है, एक को छोड़कर सभी समाधान, इस तरह की सूची में विफल होते हैं:

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

जहां वांछित उत्पादन है

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

या शायद इससे भी बेहतर, एक पुनरावृत्त। एकमात्र समाधान जो मैंने देखा कि एक मनमाना घोंसले के लिए काम करता है इस प्रश्न में पाया जाता है :

def flatten(x):
    result = []
    for el in x:
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

flatten(L)

क्या यह सबसे अच्छा मॉडल है? क्या मैंने कुछ अनदेखी की? काई समस्या?


16
तथ्य यह है कि इस सवाल पर कई जवाब और इतनी कार्रवाई है कि वास्तव में यह कहीं न कहीं एक अंतर्निहित कार्य होना चाहिए? यह विशेष रूप से बहुत बुरा है कंपाइलर। पायथन 3.0 से हटा दिया गया था
Mittenchops

3
मैं कहूंगा कि पायथन को वास्तव में एक अन्य बिलिन की बजाय अटूट पुनरावृत्ति की आवश्यकता है।
क्ले

2
@Mittenchops: पूरी तरह से असहमत, तथ्य यह है कि लोगों को स्पष्ट रूप से बुरा एपीआई / अत्यधिक जटिल डेटा संरचनाओं के साथ काम करने वाले (बस एक नोट: listसजातीय होने का इरादा है) इसका मतलब यह नहीं है कि यह पायथन की गलती है और हमें इस तरह के कार्य के लिए एक
बिल्डिन की

1
यदि आप अपनी परियोजना में एक पैकेज जोड़ सकते हैं - तो मुझे लगता है कि और अधिक_टेरिटुलेसकोलॉसेप समाधान इसे सबसे अच्छा करेगा। इस उत्तर से: stackoverflow.com/a/40938883/3844376
viddik13

जवाबों:


382

जनरेटर फ़ंक्शन का उपयोग करने से आपके उदाहरण को पढ़ने में थोड़ी आसानी हो सकती है और शायद प्रदर्शन को बढ़ावा मिल सकता है।

अजगर २

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flatten(el):
                yield sub
        else:
            yield el

मैंने 2.6 में जोड़ा Iterable ABC का उपयोग किया ।

अजगर ३

पायथन 3 में, basestringकोई और अधिक नहीं है, लेकिन आप एक टपल का उपयोग कर सकते हैं strऔर bytesवहां समान प्रभाव प्राप्त कर सकते हैं ।

yield fromऑपरेटर एक समय में एक जनरेटर एक से एक आइटम देता है। सबगेंनेटर में प्रतिनिधि के लिए यह सिंटैक्स 3.3 में जोड़ा गया था

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el

6
इस पृष्ठ के सभी सुझावों में से, यह एकमात्र है जिसने इस सूची l = ([[chr(i),chr(i-32)] for i in xrange(ord('a'), ord('z')+1)] + range(0,9))को एक स्नैप में समतल किया जब मैंने ऐसा किया list(flatten(l))। अन्य सभी, काम करना शुरू कर देंगे और हमेशा के लिए ले जाएंगे!
nemesisfixx

7
यह भी शब्दकोश को समतल करता है। शायद आप collections.Sequenceइसके बजाय उपयोग करना चाहते हैं collections.Iteratable?
जोस

1
यह उन चीजों के साथ काम नहीं करता है जो शुरू में सूचीबद्ध नहीं हैं, जैसे for i in flatten(42): print (i)। इसे isinstance-loest और -loop के बाहर अन्य-क्लॉज को ले जाकर ठीक किया जा सकता है for el। (तब आप इस पर कुछ भी फेंक सकते हैं, और यह एक चपटी सूची बना देगा)
रोलाकौ

6
पायथॉन 3.7 के लिए, का उपयोग collections.Iterableकरना पदावनत है। collections.abc.Iterableइसके बजाय उपयोग करें ।
dawg

5
वास्तव में, पुनरावृत्ति की कभी आवश्यकता नहीं होती है। इस विशिष्ट मामले में पुनरावृत्ति का उपयोग करना सबसे अच्छा समाधान नहीं है क्योंकि यह गहरी नेस्टेड सूचियों (गहराई> 1000) पर दुर्घटनाग्रस्त हो जाएगा। लेकिन अगर आप कुछ सुरक्षित रखने का लक्ष्य नहीं रखते हैं, तो हाँ पुनरावर्ती कार्य बेहतर हैं क्योंकि वे पढ़ने / लिखने में आसान हैं।
cglacet

50

मेरा समाधान:

import collections


def flatten(x):
    if isinstance(x, collections.Iterable):
        return [a for i in x for a in flatten(i)]
    else:
        return [x]

थोड़ा और संक्षिप्त, लेकिन बहुत ज्यादा एक ही।


5
आप बिना किसी आयात के ऐसा कर सकते हैं यदि आप try: iter(x)परीक्षण करना चाहते हैं कि क्या यह चलने योग्य है ... लेकिन मुझे नहीं लगता कि एक स्टडलिब मॉड्यूल आयात करने से बचना एक नकारात्मक पहलू है।
8

8
ध्यान दें कि यह समाधान केवल तभी काम करता है जब सभी आइटम प्रकार के होंint
अल्फ़ासिन

1
इसे और अधिक संक्षिप्त बना सकता है, def flatten(x): return [a for i in x for a in flatten(i)] if isinstance(x, collections.Iterable) else [x]- लेकिन पठनीयता यहां व्यक्तिपरक हो सकती है।
शून्य

4
यह तार पर काम नहीं करता है क्योंकि तार भी चलने योग्य हैं। शर्त को बदलेंif isinstance(x, collections.Iterable) and not isinstance(x, basestring)
anandis

36

पुनरावर्तन और बतख टाइपिंग का उपयोग कर जेनरेटर (पायथन 3 के लिए अद्यतन):

def flatten(L):
    for item in L:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

list(flatten([[[1, 2, 3], [4, 5]], 6]))
>>>[1, 2, 3, 4, 5, 6]

1
धन्यवाद, कि पायथन के लिए अच्छा काम करता है 3. 2.x के लिए पिछले की जरूरत है: for i in flatten(item): yield i
dansalmo

सूची (समतल ([[ 'एक्स'], 'वाई'])) 2.X संस्करण पर विफल रहता है
sten

@ user1019129 ऊपर अपनी टिप्पणी देखें
dansalmo

हाँ यह चक्र के साथ विफल रहता है .. मुझे लगता है क्योंकि एक स्ट्रिंग भी एक "सरणी" -of-chars है
स्टेन

35

@ Unutbu के गैर-पुनरावर्ती समाधान का जेनरेटर संस्करण, जैसा कि @Andrew द्वारा एक टिप्पणी में अनुरोध किया गया है:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        yield l[i]
        i += 1

इस जनरेटर का थोड़ा सरल संस्करण:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    while l:
        while l and isinstance(l[0], ltypes):
            l[0:1] = l[0]
        if l: yield l.pop(0)

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

6
मुझे लगता है कि आपको स्ट्रिंग्स के लिए परीक्षण करने की आवश्यकता है - उदाहरण के लिए "और क्रिस्टीन के समाधान के रूप में आइंस्टीनेंस (एल [0], बेसरेस्ट्रिंग)" नहीं। अन्यथा आपको l [0: 1] = l [0] के चारों ओर एक अनंत लूप मिलता है
c-urchin

यह जनरेटर बनाने का एक अच्छा उदाहरण है, लेकिन सी-यूरिनिन उल्लेख के अनुसार, एल्गोरिथ्म स्वयं विफल हो जाता है जब अनुक्रम में तार होते हैं।
डैनियल 'डांग' ग्रिफ़िथ

28

यहाँ पुनरावर्ती चपटे का मेरा कार्यात्मक संस्करण है जो ट्यूपल्स और सूचियों दोनों को संभालता है, और आपको स्थिति-संबंधी तर्कों के किसी भी मिश्रण में फेंकने देता है। एक जनरेटर लौटाता है, जो पूरे क्रम को क्रम में पैदा करता है, arg द्वारा arg:

flatten = lambda *n: (e for a in n
    for e in (flatten(*a) if isinstance(a, (tuple, list)) else (a,)))

उपयोग:

l1 = ['a', ['b', ('c', 'd')]]
l2 = [0, 1, (2, 3), [[4, 5, (6, 7, (8,), [9]), 10]], (11,)]
print list(flatten(l1, -2, -1, l2))
['a', 'b', 'c', 'd', -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

1
महान समाधान है, तथापि बहुत उपयोगी है, तो आप क्या वर्णन करने के लिए कुछ टिप्पणी की होगी e, a, nका उल्लेख
क्रिस्टोफ पाल

2
@WolfgangKuehne: प्रयास करें argsके लिए n, intermediate(या कम midया आप पसंद कर सकते हैंelement ) के लिए aऔर resultके लिए eहै, तो:flatten = lambda *args: (result for mid in args for result in (flatten(*mid) if isinstance(mid, (tuple, list)) else (mid,)))
अगली सूचना तक रोका गया।

की तुलना में यह काफी तेज है compiler.ast.flatten। ग्रेट, कॉम्पैक्ट कोड, किसी भी (मुझे लगता है) ऑब्जेक्ट प्रकार के लिए काम करता है।
23

वाह यह सबसे अधिक मतदान और स्वीकृत उत्तर होना चाहिए ... एक आकर्षण की तरह काम करता है!
U10- फॉरवर्ड

27

flattenअजगर के पुनरावर्तन की सीमा से बचा जाता है (और इस तरह मनमाने ढंग से गहरे, नेस्टेड iterables के साथ काम करता है)। यह एक जनरेटर है जो तार और मनमाना पुनरावृत्तियों (यहां तक ​​कि अनंत वाले) को संभाल सकता है।

import itertools as IT
import collections

def flatten(iterable, ltypes=collections.Iterable):
    remainder = iter(iterable)
    while True:
        first = next(remainder)
        if isinstance(first, ltypes) and not isinstance(first, (str, bytes)):
            remainder = IT.chain(first, remainder)
        else:
            yield first

इसके उपयोग को प्रदर्शित करने वाले कुछ उदाहरण यहां दिए गए हैं:

print(list(IT.islice(flatten(IT.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

print(list(IT.islice(flatten(IT.chain(IT.repeat(2,3),
                                       {10,20,30},
                                       'foo bar'.split(),
                                       IT.repeat(1),)),10)))
# [2, 2, 2, 10, 20, 30, 'foo', 'bar', 1, 1]

print(list(flatten([[1,2,[3,4]]])))
# [1, 2, 3, 4]

seq = ([[chr(i),chr(i-32)] for i in range(ord('a'), ord('z')+1)] + list(range(0,9)))
print(list(flatten(seq)))
# ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H',
# 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P',
# 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X',
# 'y', 'Y', 'z', 'Z', 0, 1, 2, 3, 4, 5, 6, 7, 8]

हालांकि flattenअनंत जनरेटर को संभाल सकता है, यह अनंत घोंसले को नहीं संभाल सकता है:

def infinitely_nested():
    while True:
        yield IT.chain(infinitely_nested(), IT.repeat(1))

print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs

1
एबीसी Iterable या ABC अनुक्रम का उपयोग करने पर कोई सहमति?
विम

sets, dicts, deques, listiterators, generators, Filehandles, और साथ कस्टम कक्षाओं __iter__परिभाषित के सभी उदाहरण हैं collections.Iterable, लेकिन नहीं collections.Sequence। चपटा होने का परिणाम dictथोड़ा सा iffy है, लेकिन अन्यथा, मुझे लगता collections.Iterableहै कि इससे बेहतर डिफ़ॉल्ट है collections.Sequence। यह निश्चित रूप से अधिक उदार है।
unutbu

@wim: उपयोग करने के साथ एक समस्या collections.Iterableयह है कि इसमें अनंत जनरेटर शामिल हैं। मैंने अपना उत्तर इस मामले को संभाल लिया है।
अनटुबु

1
यह तीसरे और चौथे उदाहरण के लिए काम नहीं करता है। यह फेंकता है StopIteration। इसके अलावा, ऐसा लगता है कि इसके while True: first = next(remainder) द्वारा प्रतिस्थापित किया जा सकता है for first in remainder:
जॉर्जी

@Georgy यह एक में समतल के शरीर encapsulating के साथ तय किया जा सकता है try-except StopIteration block
बैडुकर

12

यहां एक और जवाब है जो और भी दिलचस्प है ...

import re

def Flatten(TheList):
    a = str(TheList)
    b,crap = re.subn(r'[\[,\]]', ' ', a)
    c = b.split()
    d = [int(x) for x in c]

    return(d)

मूल रूप से, यह नेस्टेड सूची को एक स्ट्रिंग में परिवर्तित करता है, नेस्टेड सिंटैक्स को स्ट्रिप करने के लिए एक रेगेक्स का उपयोग करता है, और फिर परिणाम को एक (चपटा) सूची में परिवर्तित करता है।


यदि आप इसे अंतर मानों के अलावा किसी अन्य चीज़ के लिए सामान्यीकृत करने का प्रयास करते हैं, तो यह मज़ेदार होगा, उदाहरण के लिए [['C=64', 'APPLE ]['], ['Amiga', 'Mac', 'ST']]: :) दूसरी ओर, एक सूची दी गई जिसमें स्वयं शामिल है, यह अन्य उत्तरों की तुलना में थोड़ा बेहतर होगा, केवल लूपिंग के बजाय जब तक आप मेमोरी से बाहर नहीं निकलते / तब तक
पीछे हटते हैं

मूल संकेत पूर्णांक की सूची को समतल करने के बारे में था। यदि आप सिर्फ सूची समझ को d = [x के लिए x में c में बदलते हैं] तो यह आपके नमूने के लिए ठीक काम करना चाहिए।
मिट्टी

सबसे पहले, [x for x in c]बस एक धीमी और क्रियात्मक तरीका है जिसकी एक प्रतिलिपि बनाने के लिए c, तो आप ऐसा क्यों करेंगे? दूसरा, अपने कोड स्पष्ट रूप से परिवर्तित करने के लिए जा रहा है 'APPLE ]['में 'APPLE 'है, क्योंकि यह हवाले से संभाल नहीं है, यह सिर्फ मान लिया गया है किसी भी कोष्ठक सूची कोष्ठक हैं।
बजे

हा! जिस तरह से आपकी टिप्पणी मेरे कंप्यूटर पर स्वरूपित हुई, मुझे यह भी महसूस नहीं हुआ कि यह Apple II होना चाहिए था क्योंकि यह पुराने कंप्यूटरों पर दिखाई देता था। किसी भी स्थिति में, आपके दोनों प्रश्नों का मेरा उत्तर यह है कि यह अभ्यास - मेरे लिए - एक सूची को समतल करने के लिए एक रचनात्मक समाधान खोजने के लिए एक प्रयोग मात्र है। मुझे यकीन नहीं है कि मैं हर सूची को वहां से समतल करने के लिए इसे सामान्य करूंगा।
क्ले

तुम बस की जरूरत है arr_str = str(arr)और फिर [int(s) for s in re.findall(r'\d+', arr_str)]वास्तव में। देखिए github.com/jorgeorpinel/flatten_nested_lists/blob/master/…
जॉर्ज ऑर्पीनेल

10
def flatten(xs):
    res = []
    def loop(ys):
        for i in ys:
            if isinstance(i, list):
                loop(i)
            else:
                res.append(i)
    loop(xs)
    return res

8

आप deepflattenतृतीय पक्ष पैकेज से उपयोग कर सकते हैं iteration_utilities:

>>> from iteration_utilities import deepflatten
>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(deepflatten(L))
[1, 2, 3, 4, 5, 6]

>>> list(deepflatten(L, types=list))  # only flatten "inner" lists
[1, 2, 3, 4, 5, 6]

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

>>> %timeit list(deepflatten(L))
12.6 µs ± 298 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit list(deepflatten(L, types=list))
8.7 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> %timeit list(flatten(L))   # Cristian - Python 3.x approach from https://stackoverflow.com/a/2158532/5393381
86.4 µs ± 4.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(flatten(L))   # Josh Lee - https://stackoverflow.com/a/2158522/5393381
107 µs ± 2.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(genflat(L, list))  # Alex Martelli - https://stackoverflow.com/a/2159079/5393381
23.1 µs ± 710 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

मैं iteration_utilitiesपुस्तकालय का लेखक हूं ।


7

यह एक ऐसा समारोह बनाने की कोशिश कर रहा था जो पायथन में अनियमित सूची को समतल कर सके, लेकिन निश्चित रूप से वह है जो पायथन के लिए है (प्रोग्रामिंग को मजेदार बनाने के लिए)। निम्नलिखित जनरेटर कुछ caveats के साथ काफी अच्छी तरह से काम करता है:

def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable

यह डेटाटाइप्स आप अकेला छोड़ दिया चाहते हो सकता है कि (जैसे समतल होगा bytearray, bytesऔर strवस्तुओं)। इसके अलावा, कोड इस तथ्य पर निर्भर करता है कि गैर-पुनरावृत्ति से पुनरावृत्ति का अनुरोध करने से ए उठता है TypeError

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable


>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>>

संपादित करें:

मैं पिछले कार्यान्वयन से असहमत हूं। समस्या यह है कि आपको ऐसी चीज़ को समतल करने में सक्षम नहीं होना चाहिए जो एक चलने योग्य नहीं है। यह भ्रामक है और तर्क की गलत धारणा देता है।

>>> list(flatten(123))
[123]
>>>

निम्नलिखित जनरेटर लगभग पहले जैसा ही है, लेकिन इसमें एक गैर-पुनरावृत्त वस्तु को समतल करने की कोशिश करने की समस्या नहीं है। यह विफल हो जाता है क्योंकि कोई उम्मीद करता है कि जब कोई अनुचित तर्क दिया जाएगा।

def flatten(iterable):
    for item in iterable:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

जनरेटर का परीक्षण उस सूची के साथ ठीक काम करता है जो प्रदान की गई थी। हालाँकि, नया कोड TypeErrorतब उठाया जाएगा जब एक गैर-चलने योग्य वस्तु उसे दी जाएगी। उदाहरण नए व्यवहार के नीचे दिखाए गए हैं।

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>> list(flatten(123))
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    list(flatten(123))
  File "<pyshell#27>", line 2, in flatten
    for item in iterable:
TypeError: 'int' object is not iterable
>>>

5

हालांकि एक सुरुचिपूर्ण और बहुत ही आकर्षक जवाब का चयन किया गया है, मैं सिर्फ समीक्षा के लिए अपना समाधान प्रस्तुत करूंगा:

def flat(l):
    ret = []
    for i in l:
        if isinstance(i, list) or isinstance(i, tuple):
            ret.extend(flat(i))
        else:
            ret.append(i)
    return ret

कृपया बताएं कि यह कोड कितना अच्छा या बुरा है?


1
का उपयोग करें isinstance(i, (tuple, list))। वैकल्पिक कोड संरचनाओं को देखने के लिए खाली चर को शुरू करना मेरे लिए एक ध्वज है, आमतौर पर समझ, जनरेटर, पुनरावृत्ति, आदि
dansalmo

3
return type(l)(ret)आपको उसी कंटेनर प्रकार वापस मिल जाएगा जैसा कि अंदर पारित किया गया था, भी। :)
डैश-टॉम-बैंग

@ डैश-टॉम-बैंग क्या आप इसे थोड़ा विस्तार से बता सकते हैं।
34:३४ पर एक्सक्लूसिव

1
यदि आप किसी सूची में पास होते हैं, तो आप संभवतः एक सूची वापस चाहते हैं। यदि आप एक ट्यूपल में गुजरते हैं, तो आप शायद एक टपल वापस चाहते हैं। यदि आप दोनों के एक मिश्मश में पास हो जाते हैं, तो आपको बाहरी संलग्न वस्तु जो कुछ भी थी, मिल जाएगी।
डैश-टॉम-बैंग

4

मैं सरल उत्तर पसंद करता हूं। कोई जनरेटर नहीं। कोई पुनरावृत्ति या पुनरावृत्ति सीमा नहीं। बस पुनरावृत्ति:

def flatten(TheList):
    listIsNested = True

    while listIsNested:                 #outer loop
        keepChecking = False
        Temp = []

        for element in TheList:         #inner loop
            if isinstance(element,list):
                Temp.extend(element)
                keepChecking = True
            else:
                Temp.append(element)

        listIsNested = keepChecking     #determine if outer loop exits
        TheList = Temp[:]

    return TheList

यह दो सूचियों के साथ काम करता है: लूप के लिए एक आंतरिक और लूप के समय एक बाहरी।

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

वे पास तब तक होते रहते हैं जब तक कोई और नेस्टेड सूची नहीं मिलती। जब एक पास अंत में होता है जहां कोई भी नहीं पाया जाता है, तो चेकचेकिंग कभी भी सच होने की कोशिश नहीं करता है, जिसका अर्थ है कि सूचीबद्ध झूठी और बाहरी रहता है जबकि लूप बाहर निकलता है।

चपटी सूची फिर वापस आ जाती है।

परीक्षण चालन

flatten([1,2,3,4,[100,200,300,[1000,2000,3000]]])

[1, 2, 3, 4, 100, 200, 300, 1000, 2000, 3000]


मुझे सिंपल भी अच्छा लगता है। हालांकि इस मामले में, आप सूची में अधिक से अधिक बार ऐसा करते हैं जैसे कि घोंसले या स्तर हैं। महंगा हो सकता है।
टेलियोट९९

@ telliott99: यदि आपकी सूचियाँ वास्तव में बड़ी हैं और / या बड़ी गहराई तक घोंसला बनाया है तो आप सही हैं। हालांकि, अगर ऐसा नहीं है, तो सरल समाधान बस के रूप में अच्छी तरह से काम करता है, और कुछ अन्य उत्तरों के गहरे जादू के बिना। बहु-चरण पुनरावर्ती जनरेटर समझ के लिए एक जगह है, लेकिन मुझे विश्वास नहीं है कि जहां आपको पहले देखना चाहिए। (मुझे लगता है कि आपको पता है कि मैं "वॉर्ज़ इज बेटर" डिबेट में कहां हूं।)
मिट्टी

@ Telliott99: या उस दूसरे तरीके को रखने के लिए, आपको मेरा समाधान "ग्रॉक करने की कोशिश" नहीं करना होगा। यदि प्रदर्शन एक अड़चन नहीं है, तो प्रोग्रामर के रूप में आपके लिए क्या मायने रखता है?
मिट्टी

सरल समाधानों में तर्क कम होते हैं। रिकर्सियन एक सुंदर मौलिक प्रोग्रामिंग कंस्ट्रक्शन है जो कोई भी खुद को प्रोग्रामर मानता है उसे पूरी तरह से सहज होना चाहिए। जेनरेटर बहुत अधिक हैं पायथन वे और (समझ के साथ) कुछ ऐसे हैं जो किसी भी पेशेवर पायथन प्रोग्रामर को तुरंत ग्रो करना चाहिए।
डैश-टॉम-बैंग

1
मैं पुनरावृत्ति के बारे में सहमत हूं। जब मैंने अपना उत्तर लिखा, तब भी अजगर ने 1000 चक्रों में पुनरावृत्ति को तोड़ दिया। क्या उन्होंने इसे बदल दिया है? एक पेशेवर अजगर प्रोग्रामर होने के नाते, मैं नहीं हूं। इसके अलावा, मैं कल्पना करता हूं कि अजगर में प्रोग्रामिंग करने वाले बहुत से लोग ऐसा नहीं करते हैं।
क्ले

4

यहां एक सरल कार्य है जो मनमानी गहराई की सूची को समतल करता है। स्टैक ओवरफ्लो से बचने के लिए कोई पुनरावृत्ति नहीं।

from copy import deepcopy

def flatten_list(nested_list):
    """Flatten an arbitrarily nested list, without recursion (to avoid
    stack overflows). Returns a new list, the original list is unchanged.

    >> list(flatten_list([1, 2, 3, [4], [], [[[[[[[[[5]]]]]]]]]]))
    [1, 2, 3, 4, 5]
    >> list(flatten_list([[1, 2], 3]))
    [1, 2, 3]

    """
    nested_list = deepcopy(nested_list)

    while nested_list:
        sublist = nested_list.pop(0)

        if isinstance(sublist, list):
            nested_list = sublist + nested_list
        else:
            yield sublist


3

मुझे आश्चर्य है कि किसी ने भी ऐसा नहीं सोचा है। धिक्कार है कि मैं यहाँ के उन्नत लोगों को पुनरावर्ती उत्तर नहीं मिला। वैसे भी इस पर मेरा प्रयास है। यह ओपी के उपयोग के मामले में बहुत विशिष्ट है

import re

L = [[[1, 2, 3], [4, 5]], 6]
flattened_list = re.sub("[\[\]]", "", str(L)).replace(" ", "").split(",")
new_list = list(map(int, flattened_list))
print(new_list)

उत्पादन:

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

3

मैं यहाँ पहले से उपलब्ध सभी उत्तरों से नहीं गुज़रा, लेकिन यहाँ एक लाइनर है जिसे मैं लेकर आया हूँ, पहले और बाकी सूची प्रसंस्करण के लिस्प के रास्ते से उधार लेना

def flatten(l): return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]

यहाँ एक सरल और एक नहीं तो साधारण मामला है -

>>> flatten([1,[2,3],4])
[1, 2, 3, 4]

>>> flatten([1, [2, 3], 4, [5, [6, {'name': 'some_name', 'age':30}, 7]], [8, 9, [10, [11, [12, [13, {'some', 'set'}, 14, [15, 'some_string'], 16], 17, 18], 19], 20], 21, 22, [23, 24], 25], 26, 27, 28, 29, 30])
[1, 2, 3, 4, 5, 6, {'age': 30, 'name': 'some_name'}, 7, 8, 9, 10, 11, 12, 13, set(['set', 'some']), 14, 15, 'some_string', 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
>>> 

यह एक लाइनर नहीं है। कोई फर्क नहीं पड़ता कि आप इसे एक में फिट करने का कितना प्रयास करते हैं, def foo():एक अलग लाइन है। इसके अलावा, यह बहुत ही अपठनीय है।
सीएस 95 95

मैंने कोड को डी-वन-लाइन-ified किया है, और कुछ और रीफैक्टरिंग किया है। (संपादन लंबित सहकर्मी समीक्षा के रूप में मैं इसे लिखता हूं) यह विशेष विधि मेरे लिए बहुत पठनीय थी, हालांकि मूल कोड को कुछ रिफैक्टिंग की आवश्यकता थी।
एमिलियो एम बुमचार

3

ऐसे प्रश्न का उत्तर देने की कोशिश करते समय आपको वास्तव में एक समाधान के रूप में प्रस्तावित कोड की सीमाएं देने की आवश्यकता होती है। यदि यह केवल प्रदर्शन के बारे में होता है तो मुझे बहुत ज्यादा बुरा नहीं लगेगा, लेकिन समाधान के रूप में प्रस्तावित अधिकांश कोड (स्वीकृत उत्तर सहित) किसी भी सूची को समतल करने में विफल होते हैं जिनकी गहराई 1000 से अधिक है।

जब मैं अधिकांश कोड कहता हूं मतलब है कि सभी कोड जो किसी भी प्रकार के पुनरावर्तन का उपयोग करते हैं (या मानक लाइब्रेरी फ़ंक्शन कहते हैं जो पुनरावर्ती है)। ये सभी कोड विफल हो जाते हैं क्योंकि किए गए प्रत्येक पुनरावर्ती कॉल के लिए, (कॉल) स्टैक एक इकाई से बढ़ता है, और (डिफ़ॉल्ट) अजगर कॉल स्टैक का आकार 1000 है।

यदि आप कॉल स्टैक से बहुत परिचित नहीं हैं, तो शायद निम्नलिखित मदद करेगा (अन्यथा आप केवल कार्यान्वयन पर स्क्रॉल कर सकते हैं )।

कॉल स्टैक आकार और पुनरावर्ती प्रोग्रामिंग (कालकोठरी सादृश्य)

खजाना ढूंढना और बाहर निकलना

कल्पना कीजिए कि आप एक विशाल कालकोठरी में गिने हुए कमरों के साथ एक खजाने की तलाश कर रहे हैं। आपको जगह का पता नहीं है लेकिन आपको कुछ संकेत हैं कि खजाने को कैसे खोजना है। प्रत्येक संकेत एक पहेली है (कठिनाई भिन्न होती है, लेकिन आप अनुमान नहीं लगा सकते हैं कि वे कितने कठिन होंगे)। आप समय बचाने के लिए एक रणनीति के बारे में थोड़ा सोचने का फैसला करते हैं, आप दो अवलोकन करते हैं:

  1. खजाना ढूंढना कठिन (लंबा) है क्योंकि आपको वहां पहुंचने के लिए (संभावित रूप से कठिन) पहेलियों को हल करना होगा।
  2. एक बार खजाना मिल जाने के बाद, प्रवेश द्वार पर वापस जाना आसान हो सकता है, आपको बस उसी दिशा का दूसरी दिशा में उपयोग करना होगा (हालाँकि यह आपके पथ को याद करने के लिए थोड़ी मेमोरी की आवश्यकता है)।

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

आप काल कोठरी में प्रवेश करते हैं, पहले 1001 पहेलियों को बड़ी सफलता के साथ हल करते हैं, लेकिन यहां कुछ ऐसा आता है जिसकी आपने योजना नहीं बनाई थी, आपके पास उधार ली गई नोटबुक में कोई जगह नहीं बची है। आप छोड़ने का फैसला करते हैं अपनी खोज करते हैं क्योंकि आप कालकोठरी के अंदर हमेशा के लिए खो जाने की तुलना में खजाना नहीं पसंद करते हैं (जो वास्तव में स्मार्ट दिखता है)।

एक पुनरावर्ती कार्यक्रम को निष्पादित करना

मूल रूप से, यह खजाने को खोजने के समान सटीक बात है। कालकोठरी कंप्यूटर की मेमोरी है , अब आपका लक्ष्य एक खजाना ढूंढना नहीं है, बल्कि किसी फ़ंक्शन ( किसी दिए गए x के लिए f (x) का पता लगाना ) की गणना करना है । संकेत बस उप-रूटीन हैं जो आपको एफ (एक्स) को हल करने में मदद करेंगे । आपकी रणनीति कॉल स्टैक रणनीति के समान है, नोटबुक स्टैक है, कमरे फ़ंक्शंस पते हैं:

x = ["over here", "am", "I"]
y = sorted(x) # You're about to enter a room named `sorted`, note down the current room address here so you can return back: 0x4004f4 (that room address looks weird)
# Seems like you went back from your quest using the return address 0x4004f4
# Let's see what you've collected 
print(' '.join(y))

कालकोठरी में आपके सामने जो समस्या है वही यहाँ होगी, कॉल स्टैक का परिमित आकार (यहाँ 1000) है और इसलिए, यदि आप बिना वापस लौटते हुए बहुत सारे कार्य करते हैं तो आप कॉल स्टैक को भर देंगे और एक त्रुटि होगी जो देखो जैसे "प्रिय साहसी, मुझे बहुत खेद है, लेकिन आपकी नोटबुक भरी हुई है" : जो कि एक बार - बार-बार कॉल करता है - आप गणना खत्म होने तक और खजाने के खत्म होने तक प्रवेश करेंगे । जब तक आप उस स्थान पर वापस नहीं जाते हैं जहां आपने पहली जगह पर बुलाया था। कॉल स्टैक को कभी भी किसी भी चीज से मुक्त नहीं किया जाएगा, जहां अंत तक यह एक के बाद एक सभी रिटर्न एड्रेस से मुक्त हो जाएगा।RecursionError: maximum recursion depth exceeded । ध्यान दें कि आपको कॉल स्टैक को भरने के लिए पुनरावृत्ति की आवश्यकता नहीं है, लेकिन यह बहुत ही संभावना नहीं है कि एक गैर-पुनरावर्ती कार्यक्रम 1000 कार्यों को कभी भी वापस न करे। यह समझना भी महत्वपूर्ण है कि एक बार जब आप किसी फ़ंक्शन से लौटते हैं, तो कॉल स्टैक उपयोग किए गए पते से मुक्त हो जाता है (इसलिए नाम "स्टैक", रिटर्न पता किसी फ़ंक्शन में प्रवेश करने से पहले धकेल दिया जाता है और वापस लौटते समय बाहर निकाला जाता है)। एक साधारण पुनरावृत्ति के विशेष मामले में (एक फ़ंक्शनffff

इस मुद्दे से कैसे बचें?

यह वास्तव में बहुत आसान है: "यदि आप नहीं जानते कि यह कितना गहरा जा सकता है" पुनरावृत्ति का उपयोग न करें। यह हमेशा सही नहीं होता है क्योंकि कुछ मामलों में टेल कॉल रिक्रिएशन को ऑप्टिमाइज़ (TCO) किया जा सकता है । लेकिन अजगर में, यह मामला नहीं है, और यहां तक ​​कि "अच्छी तरह से लिखा गया" पुनरावर्ती फ़ंक्शन स्टैक उपयोग का अनुकूलन नहीं करेगा । इस सवाल के बारे में गुइडो से एक दिलचस्प पोस्ट है: टेल रिकर्सन एलिमिनेशन

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

  1. वर्तमान सूची धक्का addressऔर indexएक में stackजब एक नया sublist में प्रवेश (नोट एक सूची पता + सूचकांक भी एक पता है कि, इसलिए हम सिर्फ कॉल स्टैक द्वारा इस्तेमाल किया ठीक उसी तकनीक का उपयोग करें);
  2. जब भी कोई वस्तु मिलती है, yieldवह (या उन्हें सूची में जोड़ें);
  3. एक सूची पूरी तरह से खोजे जाने के बाद, stack वापसी address(और index) का उपयोग करके मूल सूची में वापस जाएं

यह भी ध्यान दें कि यह एक पेड़ में डीएफएस के बराबर है जहां कुछ नोड उप-कलाकार हैं A = [1, 2]और कुछ सरल आइटम हैं: 0, 1, 2, 3, 4(के लिए L = [0, [1,2], 3, 4])। पेड़ इस तरह दिखता है:

                    L
                    |
           -------------------
           |     |     |     |
           0   --A--   3     4
               |   |
               1   2

डीएफएस ट्रैवर्सल प्री-ऑर्डर है: एल, 0, ए, 1, 2, 3, 4. याद रखें, एक क्रमिक डीएफएस को लागू करने के लिए आपको एक स्टैक की भी "आवश्यकता" है। निम्न राज्यों ( stackऔर flat_list) के लिए होने वाले परिणाम से पहले मैंने जो कार्यान्वयन प्रस्तावित किया था :

init.:  stack=[(L, 0)]
**0**:  stack=[(L, 0)],         flat_list=[0]
**A**:  stack=[(L, 1), (A, 0)], flat_list=[0]
**1**:  stack=[(L, 1), (A, 0)], flat_list=[0, 1]
**2**:  stack=[(L, 1), (A, 1)], flat_list=[0, 1, 2]
**3**:  stack=[(L, 2)],         flat_list=[0, 1, 2, 3]
**3**:  stack=[(L, 3)],         flat_list=[0, 1, 2, 3, 4]
return: stack=[],               flat_list=[0, 1, 2, 3, 4]

इस उदाहरण में, स्टैक अधिकतम आकार 2 है, क्योंकि इनपुट सूची (और इसलिए पेड़) की गहराई 2 है।

कार्यान्वयन

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

def flatten(iterable):
    return list(items_from(iterable))

def items_from(iterable):
    cursor_stack = [iter(iterable)]
    while cursor_stack:
        sub_iterable = cursor_stack[-1]
        try:
            item = next(sub_iterable)
        except StopIteration:   # post-order
            cursor_stack.pop()
            continue
        if is_list_like(item):  # pre-order
            cursor_stack.append(iter(item))
        elif item is not None:
            yield item          # in-order

def is_list_like(item):
    return isinstance(item, list)

इसके अलावा, ध्यान दें कि is_list_likeमेरे पास है isinstance(item, list), जिसे अधिक इनपुट प्रकारों को संभालने के लिए बदला जा सकता है, यहां मैं सिर्फ सबसे सरल संस्करण चाहता था जहां (iterable) सिर्फ एक सूची है। लेकिन आप यह भी कर सकते हैं:

def is_list_like(item):
    try:
        iter(item)
        return not isinstance(item, str)  # strings are not lists (hmm...) 
    except TypeError:
        return False

यह स्ट्रिंग्स को "सरल आइटम" मानता है और इसलिए flatten_iter([["test", "a"], "b])वापस आ जाएगा ["test", "a", "b"]और नहीं ["t", "e", "s", "t", "a", "b"]। उस मामले में, iter(item)प्रत्येक आइटम पर दो बार बुलाया जाता है, आइए हम इसे क्लीनर बनाने के लिए पाठक के लिए एक अभ्यास का नाटक करते हैं।

परीक्षण और अन्य कार्यान्वयन पर टिप्पणी

अंत में, याद रखें कि आप एक असीम रूप से नेस्टेड सूची Lका उपयोग नहीं कर सकते print(L)क्योंकि आंतरिक रूप से यह __repr__( RecursionError: maximum recursion depth exceeded while getting the repr of an object) ( ) के लिए पुनरावर्ती कॉल का उपयोग करेगा । उसी कारण से, flattenशामिल करने के समाधान strएक ही त्रुटि संदेश के साथ विफल हो जाएंगे।

यदि आपको अपने समाधान का परीक्षण करने की आवश्यकता है, तो आप एक साधारण नेस्टेड सूची बनाने के लिए इस फ़ंक्शन का उपयोग कर सकते हैं:

def build_deep_list(depth):
    """Returns a list of the form $l_{depth} = [depth-1, l_{depth-1}]$
    with $depth > 1$ and $l_0 = [0]$.
    """
    sub_list = [0]
    for d in range(1, depth):
        sub_list = [d, sub_list]
    return sub_list

कौन देता है: build_deep_list(5)>>> [4, [3, [2, [1, [0]]]]]


2

यहाँ compiler.ast.flatten2.7.5 में कार्यान्वयन है:

def flatten(seq):
    l = []
    for elt in seq:
        t = type(elt)
        if t is tuple or t is list:
            for elt2 in flatten(elt):
                l.append(elt2)
        else:
            l.append(elt)
    return l

बेहतर, तेज़ विधियाँ हैं (यदि आप यहाँ तक पहुँच चुके हैं, तो आप उन्हें पहले ही देख चुके हैं)

यह भी नोट करें:

संस्करण 2.6 के बाद से पदावनत: पायथन 3 में संकलक पैकेज को हटा दिया गया है।


2

पूरी तरह से हैकी लेकिन मुझे लगता है कि यह काम करेगा (आपके data_type के आधार पर)

flat_list = ast.literal_eval("[%s]"%re.sub("[\[\]]","",str(the_list)))

2

बस एक funcyपुस्तकालय का उपयोग करें : pip install funcy

import funcy


funcy.flatten([[[[1, 1], 1], 2], 3]) # returns generator
funcy.lflatten([[[[1, 1], 1], 2], 3]) # returns list

1
FYI करें: यह पुनरावर्ती समाधान का उपयोग करता है: स्रोत का लिंक
Georgy

1

यहाँ एक और py2 दृष्टिकोण है, मुझे यकीन नहीं है कि अगर यह सबसे तेज़ या सबसे सुरुचिपूर्ण और न ही सबसे सुरक्षित है ...

from collections import Iterable
from itertools import imap, repeat, chain


def flat(seqs, ignore=(int, long, float, basestring)):
    return repeat(seqs, 1) if any(imap(isinstance, repeat(seqs), ignore)) or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

यह आपके द्वारा पसंद किए जाने वाले किसी भी विशिष्ट (या व्युत्पन्न) प्रकार को अनदेखा कर सकता है, यह एक पुनरावृत्ति देता है, इसलिए आप इसे किसी भी विशिष्ट कंटेनर जैसे कि सूची, टपल, तानाशाही में परिवर्तित कर सकते हैं या मेमोरी फुटप्रिंट को कम करने के लिए बेहतर या बदतर के लिए इसका उपभोग कर सकते हैं। यह इस तरह के रूप में प्रारंभिक गैर iterable वस्तुओं को संभाल कर सकते हैं ...

ध्यान दें कि अधिकांश भारी उठाने C में किया जाता है, क्योंकि जहाँ तक मुझे पता है कि itertools कैसे लागू होते हैं, इसलिए जब यह पुनरावर्ती होता है, तो AFAIK यह अजगर की पुनरावृत्ति की गहराई से बंधता नहीं है क्योंकि फ़ंक्शन कॉल C में हो रहा है, हालांकि यह इसका मतलब यह नहीं है कि आप मेमोरी से बंधे हैं, विशेष रूप से ओएस एक्स में जहां इसके स्टैक का आकार आज (ओएस एक्स मैवरिक्स) के रूप में एक कठिन सीमा है ...

थोड़ा तेज़ तरीका है, लेकिन कम पोर्टेबल तरीका है, केवल इसका उपयोग करें यदि आप यह मान सकते हैं कि इनपुट के आधार तत्व स्पष्ट रूप से निर्धारित किए जा सकते हैं, तो आपको एक अनंत पुनरावृत्ति मिलेगी, और ओएस एक्स इसके सीमित स्टैक आकार के साथ होगा, एक विभाजन गलती काफी जल्दी से फेंक ...

def flat(seqs, ignore={int, long, float, str, unicode}):
    return repeat(seqs, 1) if type(seqs) in ignore or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

यहाँ हम टाइप के लिए जाँच करने के लिए सेट का उपयोग कर रहे हैं इसलिए यह O (1) बनाम O (प्रकारों की संख्या) को यह जाँचने के लिए है कि किसी तत्व को अनदेखा किया जाना चाहिए या नहीं, हालाँकि निश्चित रूप से किसी भी प्रकार का मान लिया गया प्रकार अनदेखा हो जाएगा। , यही कारण है कि इसका उपयोग str, unicodeइसलिए सावधानी के साथ इसका उपयोग करें ...

परीक्षण:

import random

def test_flat(test_size=2000):
    def increase_depth(value, depth=1):
        for func in xrange(depth):
            value = repeat(value, 1)
        return value

    def random_sub_chaining(nested_values):
        for values in nested_values:
            yield chain((values,), chain.from_iterable(imap(next, repeat(nested_values, random.randint(1, 10)))))

    expected_values = zip(xrange(test_size), imap(str, xrange(test_size)))
    nested_values = random_sub_chaining((increase_depth(value, depth) for depth, value in enumerate(expected_values)))
    assert not any(imap(cmp, chain.from_iterable(expected_values), flat(chain(((),), nested_values, ((),)))))

>>> test_flat()
>>> list(flat([[[1, 2, 3], [4, 5]], 6]))
[1, 2, 3, 4, 5, 6]
>>>  

$ uname -a
Darwin Samys-MacBook-Pro.local 13.3.0 Darwin Kernel Version 13.3.0: Tue Jun  3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64
$ python --version
Python 2.7.5

1

किसी भी पुस्तकालय का उपयोग किए बिना:

def flat(l):
    def _flat(l, r):    
        if type(l) is not list:
            r.append(l)
        else:
            for i in l:
                r = r + flat(i)
        return r
    return _flat(l, [])



# example
test = [[1], [[2]], [3], [['a','b','c'] , [['z','x','y']], ['d','f','g']], 4]    
print flat(test) # prints [1, 2, 3, 'a', 'b', 'c', 'z', 'x', 'y', 'd', 'f', 'g', 4]

1

का उपयोग कर itertools.chain:

import itertools
from collections import Iterable

def list_flatten(lst):
    flat_lst = []
    for item in itertools.chain(lst):
        if isinstance(item, Iterable):
            item = list_flatten(item)
            flat_lst.extend(item)
        else:
            flat_lst.append(item)
    return flat_lst

या जंजीर के बिना:

def flatten(q, final):
    if not q:
        return
    if isinstance(q, list):
        if not isinstance(q[0], list):
            final.append(q[0])
        else:
            flatten(q[0], final)
        flatten(q[1:], final)
    else:
        final.append(q)

1

मैंने किसी भी गहराई के साथ नेस्टेड सूची को हल करने के लिए पुनरावर्ती का उपयोग किया

def combine_nlist(nlist,init=0,combiner=lambda x,y: x+y):
    '''
    apply function: combiner to a nested list element by element(treated as flatten list)
    '''
    current_value=init
    for each_item in nlist:
        if isinstance(each_item,list):
            current_value =combine_nlist(each_item,current_value,combiner)
        else:
            current_value = combiner(current_value,each_item)
    return current_value

इसलिए मैं फंक्शन कॉम्बिनेशन_लिंक को परिभाषित करने के बाद, इस फंक्शन को फ्लैट करना प्रयोग करना आसान है। या आप इसे एक फ़ंक्शन में जोड़ सकते हैं। मुझे अपना समाधान पसंद है क्योंकि इसे किसी भी नेस्टेड सूची पर लागू किया जा सकता है।

def flatten_nlist(nlist):
    return combine_nlist(nlist,[],lambda x,y:x+[y])

परिणाम

In [379]: flatten_nlist([1,2,3,[4,5],[6],[[[7],8],9],10])
Out[379]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

"किसी भी गहराई के साथ नेस्टेड सूची" सच नहीं है। बस आप देखेंगे की कोशिश करें: current_value = combiner(current_value,each_item) RecursionError: maximum recursion depth exceeded
cglacet

हममम आप 1000 से अधिक परतों के साथ सूची को समतल करने की कोशिश कर रहे हैं?
Oldyoung

बेशक, यह पुनरावर्ती बनाम पुनरावृत्त समाधान के बारे में चर्चा का पूरा बिंदु है। यदि आप पहले से जानते हैं कि परतों की संख्या <1000 से अधिक है तो सबसे सरल समाधान काम करेगा। जब आप "कोई भी गहराई" कहते हैं तो इसमें गहराई> 1000 के साथ सूची शामिल होती है।
cglacet

1

सबसे आसान तरीका है मॉर्फ लाइब्रेरी का उपयोग करना pip install morph

कोड है:

import morph

list = [[[1, 2, 3], [4, 5]], 6]
flattened_list = morph.flatten(list)  # returns [1, 2, 3, 4, 5, 6]

1

मुझे पता है कि पहले से ही कई भयानक उत्तर हैं, लेकिन मैं एक जवाब जोड़ना चाहता था जो प्रश्न को हल करने की कार्यात्मक प्रोग्रामिंग विधि का उपयोग करता है। इस उत्तर में मैं दोहरे पुनरावर्तन का उपयोग करता हूं:

def flatten_list(seq):
    if not seq:
        return []
    elif isinstance(seq[0],list):
        return (flatten_list(seq[0])+flatten_list(seq[1:]))
    else:
        return [seq[0]]+flatten_list(seq[1:])

print(flatten_list([1,2,[3,[4],5],[6,7]]))

उत्पादन:

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

1

मुझे यकीन नहीं है कि यह आवश्यक रूप से जल्दी या अधिक प्रभावी है, लेकिन यह वही है जो मैं करता हूं:

def flatten(lst):
    return eval('[' + str(lst).replace('[', '').replace(']', '') + ']')

L = [[[1, 2, 3], [4, 5]], 6]
print(flatten(L))

यहां flattenफ़ंक्शन एक स्ट्रिंग में सूची को बदल देता है, सभी वर्ग कोष्ठक को बाहर निकालता है , चौकोर कोष्ठक को छोर पर वापस जोड़ता है, और इसे वापस सूची में बदल देता है।

हालाँकि, अगर आपको पता था कि स्ट्रिंग्स में आपकी सूची में वर्ग कोष्ठक होंगे, जैसे [[1, 2], "[3, 4] and [5]"], आपको कुछ और करना होगा।


इसका सरल समाधान पर कोई लाभ नहीं है क्योंकि यह गहरी सूचियों को संसाधित करने में विफल रहता है, अर्थात "रिकर्सियन एरर: एक वस्तु की पुनरावृत्ति प्राप्त करते समय अधिकतम पुनरावर्तन गहराई"।
cglacet

1

यह अजगर 2 पर समतल करने का एक सरल कार्यान्वयन है

flatten=lambda l: reduce(lambda x,y:x+y,map(flatten,l),[]) if isinstance(l,list) else [l]

test=[[1,2,3,[3,4,5],[6,7,[8,9,[10,[11,[12,13,14]]]]]],]
print flatten(test)

#output [1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

1

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

def flatten_obj(n_obj, key=True, my_sep=''):
    my_string = ''
    if type(n_obj) == list:
        for val in n_obj:
            my_sep_setter = my_sep if my_string != '' else ''
            if type(val) == list or type(val) == dict:
                my_string += my_sep_setter + flatten_obj(val, key, my_sep)
            else:
                my_string += my_sep_setter + val
    elif type(n_obj) == dict:
        for k, v in n_obj.items():
            my_sep_setter = my_sep if my_string != '' else ''
            d_val = k if key else v
            if type(v) == list or type(v) == dict:
                my_string += my_sep_setter + flatten_obj(v, key, my_sep)
            else:
                my_string += my_sep_setter + d_val
    elif type(n_obj) == str:
        my_sep_setter = my_sep if my_string != '' else ''
        my_string += my_sep_setter + n_obj
        return my_string
    return my_string

print(flatten_obj(['just', 'a', ['test', 'to', 'try'], 'right', 'now', ['or', 'later', 'today'],
                [{'dictionary_test': 'test'}, {'dictionary_test_two': 'later_today'}, 'my power is 9000']], my_sep=', ')

पैदावार:

just, a, test, to, try, right, now, or, later, today, dictionary_test, dictionary_test_two, my power is 9000

0

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

def f(E):
    if E==[]: 
        return []
    elif type(E) != list: 
        return [E]
    else:
        a = f(E[0])
        b = f(E[1:])
        a.extend(b)
        return a

मैंने वास्तव में इसे कुछ अभ्यास योजना कोड से अनुकूलित किया था जो मैंने कुछ समय पहले लिखा था।

का आनंद लें!


0

मैं अजगर के लिए नया हूं और लिस्प बैकग्राउंड से आता हूं। यह वही है जिसके साथ मैं आया था (लुलज़ के लिए विभिन्न नामों की जाँच करें):

def flatten(lst):
    if lst:
        car,*cdr=lst
        if isinstance(car,(list,tuple)):
            if cdr: return flatten(car) + flatten(cdr)
            return flatten(car)
        if cdr: return [car] + flatten(cdr)
        return [car]

काम करने लगता है। परीक्षा:

flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))

रिटर्न:

[1, 2, 3, 4, 5, 6, 7, 8, 1, 2]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.