john smith john smith - 3 months ago 18
Python Question

Flatten an irregular list of lists in Python recursively

I searched and found question with same heading is also (here here here here here) but I am not asking that. I came across the problem:

To write a function to flatten a list. The list contains other lists, strings, or ints.

And my code for the same is

t=[]
def flatten(aList):
for i in aList:
if type(i) !=list:
t.append(i)
else:
flatten(i)

return t


But when I check the code for test cases:


  1. flatten([[1], [1]])
    : The checker tells me the output is
    [1, 1, 1, 1]
    but in codeskulptor I get the correct output which is
    [1, 1]
    .

  2. flatten([[[1]], [[[5]]]])
    : The checker tells the output is
    [1, 1, 1, 1, 1, 2, 3, 3, 2, 1, 0, 4, 5, 6, 7, 1, 5]
    but in codeskulptor tells
    [1, 5]
    .



This problem exists with many test cases.
Then I checked my code in python tutor and found out that after the if statement is executed each time the list
t
is returned and at-last when the function comes to halt it returns the last edited list
t
.

How can I resolve this issue please help me with this and yes I am new to python and do not know anything about itertools, lambda function usage, generators etc. so please tell me in the context in which I can understand.

Answer

Your code is relying on a global; if the checker calls your function twice, it'll receive a longer list than expected:

>>> t = []
>>> def flatten(aList):
...     for i in aList:
...         if type(i) !=list:
...              t.append(i)
...         else:
...              flatten(i)
...     return t
...
>>> flatten([1, 1])
[1, 1]
>>> flatten([1, 1])
[1, 1, 1, 1]
>>> t  # your global, still holding all those values:
[1, 1, 1, 1]

Don't use globals. Use a local list, and and extend it with the result of recursive calls:

def flatten(aList):
    t = []
    for i in aList:
        if not isinstance(i, list):
             t.append(i)
        else:
             t.extend(flatten(i))
    return t

Note that I switched to using isinstance() to test for the type. This version doesn't suffer from shared state leaking into the next call:

>>> def flatten(aList):
...     t = []
...     for i in aList:
...         if not isinstance(i, list):
...              t.append(i)
...         else:
...              t.extend(flatten(i))
...     return t
...
>>> flatten([1, 1])
[1, 1]
>>> flatten([1, 1])
[1, 1]
>>> flatten([[[1]], [[[5]]]])
[1, 5]
>>> flatten([1, 1, [42, 81]])
[1, 1, 42, 81]