1

I have one trouble in my program I´m currently working on. I need to make a function, which flatten a list whom items can contain lists again, into a one simple list. Function gets a list as a parameter and I need to return new flattened list without changing the main one, using recursion.

This is my current attempt:

 result = []

def flatten(nested_list):
    for i in nested_list:
        if type(i) != list:
            result.append(i)
        else:
            flatten(i)
    return result

The problem here is, as soon as I want to run this function again, it remembers the last result, what means that it appends everything at the end. But I want to make a new result, containing just a simple list of current nested one. How can I remove last result when calling function again?

Thanks.

fin1010
  • 69
  • 1
  • 5

3 Answers3

1

The problem here is you are always using a global variable. Using mutable global scope is generally an anti-pattern. Keeping your code essentially the same. An easy approach is to use an accumulator and pass it as an argument to your recursive calls:

In [4]: def flatten(nested_list, result=None):
   ...:     if result is None:
   ...:         result = []
   ...:     for i in nested_list:
   ...:         if type(i) != list:
   ...:             result.append(i)
   ...:         else:
   ...:             flatten(i, result)
   ...:     return result
   ...:
   ...:

In [5]: x = [[1,[2], [3,4],5]]

In [6]: flatten(x)
Out[6]: [1, 2, 3, 4, 5]

In [7]: x
Out[7]: [[1, [2], [3, 4], 5]]

In [8]: flatten(x)
Out[8]: [1, 2, 3, 4, 5]

In [9]: x
Out[9]: [[1, [2], [3, 4], 5]]

Often, though, you don't want to expose result as a parameter waiting for you to shoot yourself in the foot. So, you can define a "private" helper function:

In [15]: def _flatten(nested_list, result):
    ...:     for i in nested_list:
    ...:         if type(i) != list:
    ...:             result.append(i)
    ...:         else:
    ...:             _flatten(i, result)
    ...:     return result
    ...:
    ...: def flatten(nested_list):
    ...:     return _flatten(nested_list, [])
    ...:
    ...:

In [16]: x = [[1,[2], [3,4],5]]

In [17]: flatten(x)
Out[17]: [1, 2, 3, 4, 5]

In [18]: x
Out[18]: [[1, [2], [3, 4], 5]]

In [19]: flatten(x)
Out[19]: [1, 2, 3, 4, 5]

Or, you can define your helper inside your main function, and squirrel your result variable in a closure:

In [26]: def flatten(nested_list):
    ...:     result = []
    ...:     def _flatten(nested_list):
    ...:         for i in nested_list:
    ...:             if type(i) != list:
    ...:                 result.append(i)
    ...:             else:
    ...:                 _flatten(i)
    ...:
    ...:     _flatten(nested_list)
    ...:     return result
    ...:
    ...:

In [27]: flatten(x)
Out[27]: [1, 2, 3, 4, 5]

In [28]: x
Out[28]: [[1, [2], [3, 4], 5]]

In [29]: flatten(x)
Out[29]: [1, 2, 3, 4, 5]
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
0

The reason you are experiencing this problem is because result is in the wrong scope. You need to put the result declaration inside the function so that when the function ends, it goes out of scope and no longer exists.

Natecat
  • 2,175
  • 1
  • 17
  • 20
0

You don't need a global variable, extra argument, private helper function, nor a closure -- just know when to use append() and when to use extend():

def flatten(nested_list):
    result = []

    for i in nested_list:
        if isinstance(i, list):
            result.extend(flatten(i))
        else:
            result.append(i)

    return result

EXAMPLE

>>> x = [[1, [2], [3, 4], 5]]
>>> flatten(x)
[1, 2, 3, 4, 5]
>>> x
[[1, [2], [3, 4], 5]]
>>> 

Also if type(i) != list: probably isn't the type check of choice these days -- isinstance() will work with subclasses as well.

cdlane
  • 40,441
  • 5
  • 32
  • 81