Why blank items in flattened list

rnso Source

I am trying following recursive function to flatten sent list which may contain sublist items:

def myflatten(slist, outlist=[]):
    for sl in slist:
        if type(sl) == list:    
            outlist.append(myflatten(sl, outlist))
        else: 
            outlist.append(sl)
    return outlist

print("myflatten list=", myflatten([1,[5,6,7],3,4,[7,8,9]]))

Output:

myflatten list= [1, 5, 6, 7, [...], 3, 4, 7, 8, 9, [...]]

Why am I getting [...] for every sublist and how can I avoid getting this? Thanks for your help.

pythonpython-3.xlistrecursionflatten

Answers

answered 11 months ago NendoTaka #1

The problem is that myflatten is returning a list. So when you append the results of myflatten to the outlist it is appending a list. Try setting outlist equal to the result of myflatten:

def myflatten(slist, outlist=[]):
    for sl in slist:
        if type(sl) == list:    
            outlist = myflatten(sl, outlist) #HERE IS THE CHANGE
        else: 
            outlist.append(sl)
    return outlist

print("myflatten list=", myflatten([1,[5,6,7],3,4,[7,8,9]]))

answered 11 months ago colopop #2

You've created an infinite list. The [...] entries in the list point back to the list itself. See this answer for more details.

This is because when you make a recursive call, you pass in the outlist object itself, then return it and append it to itself. A subtle problem! But an easy fix; you'll want to use = for the recursive call, not append. Or perhaps extend, and pass in an empty list.

def myflatten(slist):
    outlist = []
    for sl in slist:
        if type(sl) == list:    
            outlist.extend(myflatten(sl))
        else: 
            outlist.append(sl)
    return outlist

You can even get rid of a parameter, which is nice.

answered 11 months ago Kevin #3

Existing answers provide good explanations to why the [...] self-reference occurs, but their suggested revisions to the code don't do anything to address the default mutable argument gotcha that's waiting to bite you.

Here's a solution that doesn't require an outlist argument:

def myflatten(slist):
    outlist = []
    for sl in slist:
        if isinstance(sl, list):    
            outlist.extend(myflatten(sl))
        else: 
            outlist.append(sl)
    return outlist

print("myflatten list=", myflatten([1,[5,6,7],3,4,[7,8,9]]))

answered 11 months ago Mr. Xcoder #4

Another option that doesn't use list.extend. I'd rearrange your code a bit, and try to avoid default parameters:

def myflatten(slist):
    flat = []
    if isinstance(slist, list):
        for item in slist:
            flat += myflatten(item)
    else:
        flat.append(slist)
    return flat

comments powered by Disqus