Just started to deal with recursion - I don’t understand everything in it yet. I think that i don\'t use a basic conditional, but i don\'t have any idea how to write it. The pro
Maybe this approach can help you understand.
It starts from the first element and sums the rest every x
ones.
That is my assumption, as you haven't provided an input and its desired output as an example.
In case you need to start from the x
th element the code can be easily modified, I leave it to you to experiment with it.
def sum_elements(nums, x) -> int:
if x>0 and x<=len(nums):
return nums[0] + sum_elements(nums[x:], x)
return 0
lst = [1, 2, 3, 4, 5, 6]
print(sum_elements(lst, 2))
print(sum_elements(lst, 3))
print(sum_elements(lst, 0))
produces
9
5
0
Note: it just demonstrates recursion, but it's not optimal for a number of reasons.
Also it discards negative values of x
Recursion is when a function calls itself and there a few (non-formal) rules that are always good to keep in the back of your mind when writing these:
Every recursion function must have a base case that acts as essentially the end of the stack in the recursive call.
non-base(s)
and the base case
.In other words, your code must be written in a way that the function either calls itself, or it terminates the recursive call. You can either do this by doing if
and else
statements, or only writing if
statements to catch the base case(s).
In math, you might remember functions that call themselves (syntax switched for the case of explanation):
f(x)_(n=0) = f(x)_(n=1) + 10
which becomes:
f(x)_(n=1) = ( f(x)_(n=2) + 10 ) + 10
and so on. In essence, you are writing this with code and setting a base case that might say (for the example above, i.e.) "stop when n
is 10". If that was the case, you should notice the cascading effect when we are layers deep into that function and when f(x)_(n=10)
makes its appearance (and lets says returns 0 + 10
) how we would have a final form of f(x)_(n=0) = 0 + 10 + 10 + 10 + ...
.
So for this function you instead have two inputs, nums
and x
. These inputs are what we will be modifying as we go down the recursion's stack.
Writing the base case is typically the easiest part of writing a recursion function. We know, for your problem, the following cases must be caught:
x
is not in the range of the length of nums
, then we must return 0
.len(nums)
is 0
, then we should return 0
.So lets begin:
def sum_elements(nums, x) -> int:
if len(nums) == 0 or not x in range(-len(nums), len(nums)):
return 0
Notice, however, that range(len([1, 2]))
will return range(0, 2)
but list(range(0, 2))
will return [0, 1]
. Therefore, we must ensure to add a 1
to our len(nums)
so that we can truly see if x
is within the proper range:
def sum_elements(nums, x) -> int:
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
Notice that range(-len(nums), len(nums) + 1)
for when nums = [1, 2, 3]
is equals to range(-3, 4)
, but list(range(-3, 4))
is equals to [-3, -2, -1, 0, 1, 2, 3]
. So therefore, we do not need a -len(nums) + 1
or -len(nums) - 1
.
Once we have figured out the base case, we can start working on our actual function. At this point we have done #1 and a portion of #2, but we now must write our non-base(s)
case(s).
other-case(s)
:As written in #2, our function input is what is dynamically changing as we go down our function stack. Therefore, we need to think about how we need to modify nums
and/or x
to fit our purposes. The first thing you should look at, however, is what would happen if we only change one of those variables as we go down the stack.
nums
constant, modify x
: We know our base case ensures x
stays within the constrain of the length of nums
in both the positive and negative direction, which is good. However, we must increment x
every time the function runs by the original x
, or x_0
. If we create the function and on every call say x + x
, we are not adding the original x
to itself, but rather adding the newer x
's to itself. This is a problem. Take the following for example:def sum_elements(nums, x) -> int:
print(nums, x)
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case. We must differentiate between positive x, and negative x.
if x > 0:
# Since x is an index that starts at 1, not 0, we must do x-1.
number = nums[x - 1]
else:
# For negative values of x this does not apply. [1, 2][-2] = 1
number = nums[x]
return number + sum_elements(nums, x + x)
Notice how we get:
# [NUMS] x
[1, 2, 3, 4, 5, 6] 2
[1, 2, 3, 4, 5, 6] 4
[1, 2, 3, 4, 5, 6] 8
# OUTPUT
6
and how the x
value on the third call is 8
. This is no bueno. The more you practice recursion, the more intuitive this concept will become on noticing how changing a certain input might not be the best. You ought to think: "what will this value be when the function continues down the stack?"
x
constant, modify nums
: If we do this way we should be certain that we will not have issues with the value of x
. The issue, then, becomes how we will modify the nums
list and use x
for our advantage. What we do know, is that x
can be technically used as an index, as demonstrated above. So, therefore, what if instead of modifying the index, we modify the list in which that index takes from? Take the following for example:nums = [1, 2, 3, 4]
x = 2
print(nums) # > [1, 2, 3, 4]
print(nums[x - 1]) # > 2
nums = nums[x:] # > [3, 4]
print(nums[x - 1]) # > 4
So it does seem like we can modify the list and keep a constant x
to retrieve the information we want. Awesome! In such case #2 is the way to go.
other-case(s)
.So now we will try to now write a function that keeps x
constant, but modifies nums
. We have a general idea from the code above, and we know from the previous point that we will have to deal with -x
and x
differently. Therefore, lets write something:
def sum_elements2(nums, x) -> int:
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case.
if x >= 0:
number = nums[x - 1]
nums = nums[x:]
else:
number = nums[x]
# Not sure what goes here.
return number + sum_elements(nums, x)
If we test the function above, it seems that it works for any positive x
, but won't work for negative values of x
. It makes sense, however, that whatever we do to the positive side, we must do the opposite to the negative side. If we try to use nums = nums[:x]
we very quickly realize it works. Our final function becomes:
def sum_elements(nums, x) -> int:
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case.
if x >= 0:
number = nums[x - 1]
nums = nums[x:]
else:
number = nums[x]
nums = nums[:x]
return number + sum_elements(nums, x)
If we run examples with the above function, we get:
print(sum_elements([1, 2, 3, 4, 5, 6], 2)) # > 2 + 4 + 6 = 12
print(sum_elements([], 0)) # > 0
print(sum_elements([1, 5, 2, 5, 9, 5], 3)) # > 7
print(sum_elements([5, 6, 10, 20], -2)) # > 15
print(sum_elements([5, 6, 10, 20], -20)) # > 0