FAQ: Recursion: Python - No Nested Lists Anymore, I Want Them to Turn Flat

This community-built FAQ covers the “No Nested Lists Anymore, I Want Them to Turn Flat” exercise from the lesson “Recursion: Python”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Learn Recursion: Python

FAQs on the exercise No Nested Lists Anymore, I Want Them to Turn Flat

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

1 Like

Hi, can anyone help here? what I understood so far (after learning Python for 2 months) is that we dont have to explicitly write “else” for an else statement, as long as we indent it on the same level as the if statment that should work. However, in the codes below, not using “else” has resulted of a different output…not sure why…

#this one is the model answer with “else”
def flatten(my_list):
result =
for el in my_list:
if isinstance(el, list):
print(“list found!”)
flat_list = flatten(el)
result += flat_list
else:
result.append(el)
return result

output -
[‘mercury’, ‘venus’, ‘earth’, ‘mars’, ‘jupiter’, ‘saturn’, ‘uranus’, ‘neptune’, ‘pluto’]

this one does not have else but instead "result.append(item) is indented on the same level as the if statement.

def flatten(my_list):
result =
for item in my_list:
if isinstance(item, list):
print(“list found!”)
flat_list = flatten(item)
result += flat_list
result.append(item)
return result

output - [‘mercury’, ‘venus’, ‘earth’, [‘earth’], ‘mars’, ‘jupiter’, ‘saturn’, [‘jupiter’, ‘saturn’], [[‘jupiter’, ‘saturn’]], ‘uranus’, ‘neptune’, ‘pluto’, [‘neptune’, ‘pluto’]]

2 Likes

Hello,

I think I found a bug, but I just want to double check: I’m doing the following lesson: https://www.codecademy.com/paths/computer-science/tracks/learn-recursion-python/modules/recursion-python/lessons/recursion-python/exercises/recursion-python-flatten

And my code doesn’t seem to work for step #2. I looked at the solutions really quickly, and I feel like I have the same thing going on. I went ahead and read the rest of the grayed out instructions. When I run the code, it also appears to do what it’s supposed to do. What is going on? Why can’t I pass step #2 even though I feel like I did it correctly?

I even changed the case of “L” on “list found”.

# define flatten() below...
def flatten(my_list):
  result = []
  for element in my_list:
    if isinstance(element, list):
      print("list found!")
      flat_list = flatten(element)
      result += flat_list
    else:
      result.append(element)
      print(element)
  return result
      
### reserve for testing...
planets = ['mercury', 'venus', ['earth'], 'mars', [['jupiter', 'saturn']], 'uranus', ['neptune', 'pluto']]

print(flatten(planets))

6 Likes

It didn’t like my else statement for step #2, which I think is stupid, because it still printed “list found!”, it just didn’t want to see anything other than the if statement. Oh well…

3 Likes

This is the corresponding test:

Components.OutputTerminal.hasOutput(/list found!\nlist found!\nlist found!/i)

Codecademy absolutely has the unfortunate habit of testing something slightly different from what their error message says is wrong.

Your output doesn’t match that pattern because it has additional output in it.

3 Likes
if (condition):
  do thing_A
do thing_B

When the condition is True, run the above code, the result will be do both thing_A and thing_B

if (condition):
  do thing_A
else:
  do thing_B

When the condition is True, run the above code, the result will be do thing_A only

When the condition is False, running the above two codes will be giving the same result, do thing_B only

3 Likes

what is the base case for this problem?

I just completed this exercise and wanted to check I’m understanding what’s happening.

def flatten(my_list):
    result = []
  
    for x in my_list:
        # recursive step
        if type(x) == list:
            flat_list = flatten(x)
            result += flat_list
        # base case
        else:
            result.append(x)
    
    return result

planets = ['mercury', 'venus', ['earth'], 'mars', [['jupiter', 'saturn']], 'uranus', ['neptune', 'pluto']]

I’d really appreciate it if someone could check my description of what’s happening when x in my recursive step is [['jupiter', 'saturn']] and let me know if my understanding is sound.

# Step-by-Step Explanation

# descriptors

# x1 = x in first function call
# x2 = x in recursive function call
# x3 = x in second recursive call
# result = result list in first function call
# flatten1 = result list in recursive function call
# flatten2 = result list in second recursive call

# step-by-step

# x1 = [['jupiter', 'saturn']]
# is x1 a list?
# yes
# x2 = ['jupiter', 'saturn']
# is x2 a list?
# yes
# x3 = 'jupiter'
# is x3 a list?
# no
# append x3 to result list of second recursive call
# flatten2 = result list of second recursive call = ['jupiter']
# x3 = 'saturn'
# is x3 a list?
# no 
# append x3 to result list of second recursive call
# flatten2 = result list of second recursive call = ['jupiter', 'saturn']
# flatten2 returned to recursive call
# x2 = 'jupiter'
# is x2 a list?
# no
# append x2 to result list of recursive call
# flatten1 = result list of recursive call = ['jupiter']
# x2 = 'saturn'
# is x2 a list?
# no
# append x2 to result list of recursive call
# flatten1 = result list of recursive call = ['jupiter', 'saturn']
# flatten1 returned to initial call
# result = ['mercury', 'venus', earth', 'mars'] + ['jupiter', 'saturn']
# result = ['mercury', 'venus', earth', 'mars', 'jupiter', 'saturn']

I think it can be tempting to view recursion as one big loop and try to understand the whole thing, but this can be really difficult, recursion can be complex (too many things to keep in ones head and understand all at once) when it really isn’t, usually it’s two or a few cases that are repeated and nested and it’s easier to understand each case individually and convince oneself that that everything is therefore covered.

So you would assume that you have a functioning flatten. You do, when you’re done, so this is a great assumption to make.

The base case is trivial, convince yourself that it does the right thing.
Your other case flattens each subvalue and concatenates them. Convince yourself of that this is the right thing.

That’s it, you’re done. The overall thing is only those two things, repeated many times.

Additionally I would like to make the two cases part of the function rather than the loop
So the function would test, hey, is this a list? If not, [x], otherwise, flatten each subthing, and doing something to each thing with a function… hey that already exists, don’t need to write it, map… oh wait, need to concat it too. chain.

from itertools import chain


def flatten(x):
    if isinstance(x, list):
        return chain(*map(flatten, x))
    return [x]


planets = [
    "mercury",
    "venus",
    ["earth"],
    "mars",
    [["jupiter", "saturn"]],
    "uranus",
    ["neptune", "pluto"],
]

print(list(flatten(planets)))

I think I understand where you’re coming from: aim to understand the base case and the recursive step are doing – and don’t get hung up on trying to understand, step-by-step, what’s happening.

I can’t believe you distilled my 30+ lines into one!

What are the benefits in doing this?

So, if I pass [['earth']] as an argument, the call stack looks like this:

  --    <- flatten('earth')
 ----   <- flatten(['earth'])
------  <- flatten([['earth']])

I don’t understand your function at the moment. We reach the base case with flatten('earth'), which pops off the stack and returns ['earth'] to flatten['earth'], but where is ['earth'] used to resolve flatten(['earth'])?

None that I had in mind.
I’m used to seeing this choice being made as the very first thing the function does, possibly even separate function definitions, one for each case.

“Flatten each subvalue” vs “for each subvalue either flatten it if it is a list or otherwise keep as is”
Might be a simpler loop or maybe I’m just failing to phrase one of them nicely.
Do whatever suits the situation.

The loop becomes flatmap (map then concat) when moving the condition out of it, so that’s nice.

If you think in terms of data structures, then you’d say that the whole thing is a tree, and a tree is either a bunch of subtrees or it’s a value, so the basecase of the type is a single value, and the function should be able to deal with any tree which includes a single value so …
But that’s not being done here so it doesn’t matter

flatten(['earth'])
results in the same as the input, the input is flat, nothing to do, the caller knows what to do with a flat list
the result of mapping flatten is a list of flat lists, to get a flat list from that, concat those lists

better perspective: the input is valid, and the output is a flat list (makes more sense if you limit your perspective to a single call: given some stuff, return a flat list, am i doing that? yeah. cool, done.)

Sign up to continue coding - Replit

It’s fascinating to see this problem solved using another language.

I’ll try to make use of this way of thinking about it. It sounds much more efficient than going through each step of the entire thing.

Thanks again!

Can someone explain to me what will be big O of this code, as we also have recursion inside the for loop will it be ,“N^2” or just N,
I am confused please clarify.

at the end of this example the else statement uses result.append() to add the planets to the final list that will be returned.
Can someone help me understand why using += causes each planet to be broken apart ex: result+=planet yields: [‘m’, ‘e’, ‘r’, ‘c’, ‘u’, ‘r’, ‘y’, ‘v’, ‘e’, ‘n’, ‘u’, ‘s’, ‘e’, ‘a’, ‘r’, ‘t’, ‘h’, ‘m’, ‘a’, ‘r’, ‘s’, ‘j’, ‘u’, ‘p’, ‘i’, ‘t’, ‘e’, ‘r’, ‘s’, ‘a’, ‘t’, ‘u’, ‘r’, ‘n’, ‘u’, ‘r’, ‘a’, ‘n’, ‘u’, ‘s’, ‘n’, ‘e’, ‘p’, ‘t’, ‘u’, ‘n’, ‘e’, ‘p’, ‘l’, ‘u’, ‘t’, ‘o’]
while result.append(planet) yields [‘mercury’, ‘venus’, ‘earth’, ‘mars’, ‘jupiter’, ‘saturn’, ‘uranus’, ‘neptune’, ‘pluto’]
in the if statement i used result+=flatten(planets) and that works fine.

it did the same thing in both cases, but you wanted two different things
when what you want is to append, use that.

1 Like

Sure If i want to append something use append.
Is it wrong to say .append and += both add the item to the list without creating a new list?
I’m pretty confused by your response. But searching for help elsewhere I’ve realized that when you add a 'string to a list via += it splits the string into the list.
so
a = [“cat”]
b= “dog”
a+= b
a is now [“cat”, “d”, “o”, “g”]
alternatively you can’t do a+=1234 - it will error as “int is not iterable”
is there any explanation as to what’s going on under the hood there that it’s iterating through the string?

The thing you passed to += when it “worked” did not get appended to your list. This is not what happened:

[1,2,3].append(x)
[1,2,3,x]

You have some initial state and some desired end state, and the difference between those two is what you want.
So if you look at both differences that you describe, you’ll find them to be different. You might not have thought through what exactly what that difference is, but nonetheless you have described them through what you have before and after.

You can also consider what + does.

[] + 5

This does not produce [5]
and neither does this:

a = []
a += 5

but this does:

[].append(5)

If you take a moment to flesh out the details of what you mean should happen, you’ll see the difference in what you want in both your situations.

Thank you for elaborating - much appreciated. The examples are helpful too.
I guess my only question now is my edit above

The “what’s going on under the hood of += that it iterates through the string?”