Search code examples
pythonpython-3.xlistalgorithmflat

Unwanted side effects when flattening a list


I was just testing some algorithms to flatten a list, so I created 3 lists inside a list, and then tried to flatten it. I never touch the original list, the variables are named different, but when I try to see the original list, it has been modified, any idea why this is happening?

In [63]: xxx =  [['R', 'L', 'D'], ['U', 'O', 'E'], ['C', 'S', 'O']]

In [64]: def flat_ind(lst):
    ...:     one = lst[0]
    ...:     for l in lst[1:]:
    ...:         one += l
    ...:     return one
    ...:

In [65]: flat = flat_ind(xxx)

In [66]: flat
Out[66]:  ['R', 'L', 'D', 'U', 'O', 'E', 'C', 'S', 'O']

In [67]:  xxx
Out[67]:
[['R', 'L', 'D', 'U', 'O', 'E', 'C', 'S', 'O'],
 ['U', 'O', 'E'],
 ['C', 'S', 'O']]

I understand that one is still pointing to the original lst and that is the reason it is modifying it, but still, I though that, since this was inside a function, it would not happen, more importantly

how do I make this not happen?

Thanks!


Solution

  • "I understand that one is still pointing to the original lst and that is the reason it is modifying it, but still, I though that, since this was inside a function, it would not happen,"

    That doesn't make any sense. It doesn't matter where you mutate an object, it will still be mutated.

    In any case, the mutation occurs because of this:

    one += l
    

    which is an in-place modification. You could use

    one = on + l 
    

    instead, but that would be highly inefficient. As others have pointed out, you could just copy that first list,

    one = lst[0][:]
    

    But the idiomatic way to flatten a regularly nested list like this is to simply:

    flat = [x for sub in xxx for x in sub]
    

    Or,

    from itertools import chain
    flat = list(chain.from_iterable(xxx))