1

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.

Community
  • 1
  • 1
sid597
  • 999
  • 3
  • 16
  • 31
  • The second link you have gives a working example of this function. – Morgan Thrapp Feb 15 '16 at 17:51
  • @Morgan Thrapp that code also does not solve my real problem – sid597 Feb 15 '16 at 17:53
  • Just for code styling: You should use [`isinstance()`](https://docs.python.org/3/library/functions.html#isinstance) instead of using `type() == type()`. – albert Feb 15 '16 at 17:53
  • 1
    Why not? It works for both of your test cases. If this question doesn't actually ask about your problem, you should ask a new question. – Morgan Thrapp Feb 15 '16 at 17:53
  • MY code also returns the same result but the checker tells that wrong infact my first code which I implemented was that one then I improved it to this and same problem exists – sid597 Feb 15 '16 at 17:56
  • 1
    @MorganThrapp: that question doesn't explain what is wrong with the code in this question. Sometimes it is *okay* to ask a question about a specific piece of code that doesn't work, if the OP is trying has made a good-faith attempt to figure this out on their own. Closing this as a dupe will not answer this question. – Martijn Pieters Feb 15 '16 at 18:00

1 Answers1

6

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]
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • @MorganThrapp: it is fine to ask about a good attempt to implement that. They are asking **why** their attempt doesn't work. – Martijn Pieters Feb 15 '16 at 17:57
  • @MorganThrapp: in other words, find a good dupe where the answer is "don't use a global because your state now leaks into future calls" and I'll gladly vote to close too. – Martijn Pieters Feb 15 '16 at 18:01
  • @ Martijn Pieters a silly question :Why did you use .extend(flatten(i)) why does just flatten(i) work? – sid597 Feb 15 '16 at 18:04
  • Moral? Never use globals. – Andrey Feb 15 '16 at 18:05
  • @Andrey yes a very good Moral.I read it many times but now found out what happens with defining globals – sid597 Feb 15 '16 at 18:06
  • 1
    @johnsmith: because you don't want to discard the result produced by the recursive call. A recursive function call is like any other function call, if that function returns a result, don't ignore it. – Martijn Pieters Feb 15 '16 at 18:07
  • @MartijnPieters but how is the result discarded will it not go to the base case and when it does the code under if statement appends it to list .Sorry for asking such silly questions and killing your time – sid597 Feb 15 '16 at 18:13
  • 1
    @johnsmith: try it out. Replace the `t.extend(flatten(i))` call with `flatten(i)`, and call your function with `flatten([1, [2, [3]])`. What happens? – Martijn Pieters Feb 15 '16 at 18:14
  • 1
    @johnsmith: or do something different: create a series of identical `flattenN()` functions, where `N` is a number. `flatten1()`, `flatten2()`, etc. Each function N calls N + 1. You can extend the series as far as you need to; for a list with 3 levels of nesting you only need to go to `flatten3()`. What do you think will happen when you use `t.extend(flatten2(i))` in `flatten1()`, and what do you think happens when you use just `flatten2(i)`? – Martijn Pieters Feb 15 '16 at 18:19
  • Yes I got that ! infact first I did not use t as global and was implementing the code just like this (without using extend) and was getting [1] then to resolve this I defined it global But thanks to you now I know the core problem.Thank You very much. – sid597 Feb 15 '16 at 18:19