Apologies for any possible confusion about the title. I will try my best to illustrate my question.
Context:
I just finished working on an interesting coding problem on CodeWars where I was asked to write a function to simplify a list of directions.
The input will look like ["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]
The 'SOUTH' 'NORTH' and 'EAST' 'WEST' that are next to each other shall both be deleted since it makes little sense to go north and then immediately south. And the list shall be simplified until it can't be simplified anymore.
For instance:
["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"]
shall be simplified to
['WEST']
Dummy OP wrote a clunky function that does it. But my question is about a really clever answer posted by someone else.
Code:
def dirReduc(arr):
dir = " ".join(arr)
dir2 = dir.replace("NORTH SOUTH",'').replace("SOUTH NORTH",'').replace("EAST WEST",'').replace("WEST EAST",'')
dir3 = dir2.split()
return dirReduc(dir3) if len(dir3) < len(arr) else dir3
I played with it and see that it works but just couldn't wrap my head around how.
I see that in the return statement, it shall run again unless the result has the same length as input, which is understandable. But the code uses dirReduc(dir3) which seems wrong to me.
If I run dirReduc(dir3) then my input will be dir3, but then inside the frame of the function, another dir3 is created. So now when the function goes to the final return statement it shall be return dirReduc(dir3) if len(dir3) < len(dir3) else dir3. And since len(dir3) == len(dir3)', it will just returndir3`.
In my understanding, the function will be run twice, max with each input, which is not the truth. So which part of my understanding is wrong?
Sorry for the sheer volume of words, I think after all this is a simple problem. There must be a very fundamental thing that I'm getting wrong.
2 Answers 2
Local variables in different stack frames are completely unrelated to each other, even if they share the same name. Each recursive call creates a new stack frame, so dir3 in one call is completely different from dir3 in another.
Imagine you had a non-recursive function that only reduced the path by one step:
def dirReducOneStep(arr):
dir = " ".join(arr)
dir2 = dir.replace("NORTH SOUTH",'').replace("SOUTH NORTH",'').replace("EAST WEST",'').replace("WEST EAST",'')
dir3 = dir2.split()
return dir3
print(dirReducOneStep(dirReducOneStep(dirReducOneStep(path))))
The only difference is that dirReduc calls itself on a reduced path, rather than forcing the caller to decide whether or not to call it again on the previous output.
11 Comments
dirReduc(dir3), this dir3 is established in the first stack frame, and in the run of dirReduc(dir3), the return statement will be dirReduc(dir3(2nd stack frame) if len(dir3(2nd stack frame)) < len(dir3(first stack frame). Did I get it right? Thanks again.It is a basic concept. Every function has its own stack, or let's say scope.
You can image that a function is a box. Local variables are inside the box. So if there are many functions, then there are many boxes. Every box has its own local variables. That's like:
BoxA
--variable_a
BoxB
--varibale_a
Although these two variables have the same name, they are in different boxes. So they are different varibales at all.
Further, BoxA(Actually functionA) cannot access the variable_a in BoxB, it is outside of its scope, so it is safe even these two variables have the same name.
dir3are local variables to each function execution, they are unrelated to each other.dir3generated inside the function is local variable? Which is unrelated to which? And when the return statement evaluateslen(dir3), hasn't it been changed to the local variable already?['NORTH', 'WEST', 'SOUTH']