recursive cumulative sums - python

I need to write a program that compute cumulative sums from a list of numbers with def but ONLY with recursion.
I did it, but now I need to write the same program without using the method sum, but no success so far.
Any idea?
my code:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers)==0: return numbers
return rec_cumsum(numbers[:-1])+ [sum(numbers)]
input:
1 [1,2,3]
2 [2, 2, 2, 3]
output:
1 [1,3,6]
2 [2, 4, 6, 9]
my code without sum:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) == 0: return numbers
my_list=[]
rec_cumsum(my_list + numbers)
my_list[0]=numbers[0]
rec_cumsum(my_list)
temp_sum=my_list[0]+numbers[-1]
my_list[0]=temp_sum
return my_list

I would suggest something like this without adding additional arguments:
[UPDATED]
def rec(n):
if len(n) < 2: return n
n[1] = n[0] + n[1]
return [n[0]] + rec(n[1:])
print rec([1,2,3,4])
[1, 3, 6, 10]

What you can do is: -
Create a temp list(an empty one).
Pass your original list and the empty list in your method.
Now, when you pass your list for the first time, just add the first element from your original list to it. And call the same method with the rest of the list. Starting from 1st element.
When your method is invoked after wards, you need to take a sum of last element of your temp list and first element of the original list that is now modified. And add the sum to your temp list as new element.
Finally, when the length of your original list becomes 0. Return your temp.
**Here's the code for the above steps. You can compare it with the one you have implemented, and see where you went wrong: -
def rec_cumsum(numbers):
if len(numbers) == 0 : return temp
# You need to check, if `temp` is empty, that means method is called first time.
if not temp:
temp.extend([numbers[0]]) // Just add the first element to it.
else:
# Else, get the last element from `temp`,
# add it to `first elemt` in `numbers` and add it to `temp`.
temp.extend([temp[-1] + numbers[0]])
return rec_cumsum(numbers[1:])
my_list = [2, 2, 2, 3]
temp = []
print rec_cumsum(my_list)

yet another solution would be:
def rec(n):
if len(n) < 2: return n
rest = rec(n[:-1])
return rest + [rest[-1] + n[-1]]
this one feels more intuitive to me..

Related

how to loop through each element in list and increment by one

Hello i want to ask how to loop through each element and increment every time by one this is what i want first i want to sum 0 , 1, 3 ,6 , 10 and after that sum can somebody help me about that i don't know how to tell if it is loop through each element or iterate.It should look like these examples.I am sorry!
ls = [0, 1, 3, 6, 10]
ls = [1, 3, 6, 10]
ls = [3, 6, 10]
ls = [6, 10]
ls = [10]
ls = []
Here's the problem who i want to solve it :
https://www.codewars.com/kata/5ce399e0047a45001c853c2b/train/python
I tried this but it doesn't work
def parts_sums(ls):
length_list = len(ls)
for i in range(0,length_list+1):
return length_list
Note that there is a built-in function sum() in Python that does that job probably better than any code you can write in Python.
sum([0, 1, 3, 6, 10])
However, if you want to practice writing your sum function by iterating through a list and summing all the elements, this is how you do it.
def my_sum(ls):
result = 0
for i in range(len(ls)):
result += ls[i]
return result
First of all, you need to initialize a variable to hold your result. The range() function generates all values from 0 to x. The for-loop assigns all values generated by the range function to i in order and executes the indented block below. The += assignment increments the left-hand side variable by the right-hand side expression value. At last, we return the result.
And if you prefer using a while-loop,
def my_sum(ls):
result = 0
i = 0
while i < len(ls):
result += ls[i]
i += 1
return result
It's always good to consult Python documentation when you are not sure how to use its built-in function.
If you want the accumulated sum of all items reversed, you can take a look at the accumulate function in itertools.
from itertools import accumulate
def parts_sums(ls):
return list(accumulate(ls[::-1]))[::-1] + [0]
Or if you want to implement with a loop,
def parts_sums(ls):
result = []
part_sum = 0
for item in ls[::-1]:
result.append(part_sum)
part_sum += item
result.append(part_sum)
return result[::-1]
Or if you want to do it without reversing the list (say if you want to yield the results)
def parts_sums(ls):
result = []
part_sum = sum(ls)
for item in ls:
result.append(part_sum)
part_sum -= item
result.append(part_sum)
return result
Note the algorithm is still O(n), not that time complexity matters in this case.
For the question you have mentioned in codewars, you need to loop it thro 2 loops and keep reducing the first element in the inner loop for sum.
def parts_sums(ls):
# your code
sum = []
for i in range(len(ls)):
sum_temp =0
for j in range(i,len(ls)):
sum_temp += ls[j]
sum.append(sum_temp)
sum.append(0) # for the final empty list
return sum
print(parts_sums([0, 1, 3, 6, 10]))
This test will check the execution time too. So you need to be fast.
Naive approach
You can use sum or create your own sum.
def parts_sums(ls):
return [
sum(ls[i:])
for i in range(len(ls) + 1)
]
But i means you'll need to loop in a list twice. So it will be slow.
Sneaky approach
In a list like [a, b, c, d, e] you are calculating:
[a+b+c+d+e, a+b+c+d, a+b+c, a+b, a, 0]. So let's start from last to first element. [0, a, a+b, a+b+c, a+b+c+d, a+b+c+d+e]. Now we see a cumulative iteration:
So get loop in the list, get the element, sum it with last element of the result ([0]) list and add it as the last element to the result list. Lastly reverse the result.
def parts_sums(ls):
res = [0]
for i in range(len(ls)-1, -1, -1):
res.append(res[-1] + ls[i])
return res[::-1]

Getting a function to multiply or sum based on the first element of a list

I am having some trouble writing a function that will sum all the elements of a list or multiply all the elements of a list together based on whether the first element of the list is odd or even.
I would like to get something like this.
def simpleSum(mylist):
#Write your code
number = 1
for n in mylist:
if n % 2 != 0:
return sum(mylist)
else:
number *= n
return number
print(simpleSum([1, 2, 4, 5]))
print(simpleSum([2, 4, 5, 6]))
I added the number = 1 and number *= n based on what I've seen on the internet, but I don't really understand why I have to use number = 1 and also what number *= n is doing.
I would like my output to be
12
240
but so far I keep getting
12
2
Very new to python, and I'm not really sure what I'm doing wrong. I originally tried using
for n in mylist:
if n[0] % 2 != 0:
but I kept getting an error telling me that n[0] is not scriptable.
Any brief explanation would help me tremendously. Thank you in advance.
there
The answer to your question is extremely simple. All you need to correct is your logic or your syntax.
Let us break your program down and try to understand where the error is.
def simpleSum(mylist):
#Write your code
number = 1
for n in mylist:
if n % 2 != 0:
return sum(mylist)
else:
number *= n
return number
print(simpleSum([1, 2, 4, 5]))
print(simpleSum([2, 4, 5, 6]))
The code for n in mylist returns one element of the list at a time, and not the position, so when you say n[0], it returns an error as it is not a list and doesn't have any indexes.
Next up, looking at your logical or syntax error:
If you notice carefully, n becomes the next index of the list everytime. This means that everytime it checks whether the number is odd or even. If it is odd, it returns with the sum, but if it is even, it returns with number multiplied by n. Since it returns at first entry itself, i.e, at the first index itself, this means that if the number is even, the result will be that number(because 1*n=n) and if it is odd, it will return the sum of the whole list.
To change this, the following logic is used.
Create function:
If the first index of the list i.e., mylist[0] is odd:
return the sum
Otherwise/else:
return the product
The code to reproduce this would be:
def simpleSum(mylist):
#Write your code
if mylist[0] % 2 != 0:
return sum(mylist)
else:
number = 1
for n in mylist:
number *= n
return number
print(simpleSum([1, 2, 4, 5]))
print(simpleSum([2, 4, 5, 6]))
Judging by your desired output and inputs, you want the list of numbers multiplied if the first element is even and the sum of the list of numbers if the first element is odd.
number = 1 acts as a base value for multiplication.
number *= n equals to number = number * n
Consider the following code. First, it checks whether the first value of the list is odd or even. Then it calculates and returns values accordingly.
def simpleSum(mylist):
if (mylist[0] % 2) == 0:
number = 1
for n in mylist:
number *= n
return number
else:
return sum(mylist)
print(simpleSum([1, 2, 4, 5]))
print(simpleSum([2, 4, 5, 6]))
I don't think your code is doing what you want. If I'm reading your description correctly, it sounds like you want to know whether the first element of your list is even or odd before you add or multiply all the elements together.
In that case, you want something like this:
if my_list[0] % 2 == 0:
print(sum(my_list)
else:
num = 1
for n in my_list:
num *= n
print(num)
The reason you need to set num = 1 is because num *= n multiplies num by n, and if num doesn't have an initial value, you can't multiply it by n!
you can use functools.reduce for the multiplication part
from functools import reduce
from operator import mul
def my_func(some_list):
return sum(some_list) if some_list[0] % 2 else reduce(mul, some_list)
print(my_func([1, 2, 4, 5]))
print(my_func([2, 4, 5, 6]))
output
12
240

Recursive function that returns combinations of size n chosen from list

I am trying to write a recursive function which takes as its inputs an integer n, and a list l, and returns a list of all the combinations of size n that can be chosen from the elements in l. I'm aware that I can just use itertools, but I want to become better at writing recursive functions, and I believe writing my own function will help me.
So for example, if you input:
n = 3
l = [1, 2, 3, 4]
I want the output to be:
`[ [1, 2, 3], [1, 3, 4], [2, 3, 4], [1, 2, 4] ]
So far I've written this code:
def get_combinations(l, n): # returns the possible combinations of size n from a list of chars
if len(l) == 0:
return []
elif n == 1:
return [l[0]]
newList = list()
for i in range(len(l)):
sliced_list = l[i:]
m = n - 1
#lost here, believe I need to make a recursive call somewhere with get_combinations(sliced_list, m)
return newList
I found this example of such a function for permutations helpful, but I'm struggling to implement something similar.
To clarify, I set up my base cases in the way I did because I'm expecting to pass sliced_list and m in my recursive call, and if you imagine the situation when i = 3, you'll have an empty list for sliced_list, and m will be 1 when you've gone deep enough to build up a combination. But I'm not married to these base cases.
Let me try to summarize the questions I have:
How do I produce a final result which is exactly a list of lists, instead of a list of lists of lists of lists ... (depth = n)?
What should my recursive call look like?
Am I going about this problem in exactly the wrong way?
First I would recommend that you layout your function like:
def get_combinations(array, n):
solutions = []
# all the code goes here
return solutions
That way if there's a case that's a problem, like n == 0, you can just ignore it and get a valid (empty) result. The next issue is this line is wrong:
elif n == 1:
return [array[0]]
The correct thing to do if n == 1 is to return an array with every element of the array wrapped in a list:
if n == 1:
solutions = [[element] for element in array]
This is your base case as the next layer up in the recursion will build on this. What comes next is the heart of the problem. If n > 1 and the array has content, then we need to loop over the indexes of the array. For each we'll call ourself recursively on everything past the current index and n - 1:
sub_solutions = get_combinations(array[index + 1:], n - 1)
This returns partial solutions. We need to stuff the element at the current index, ie. array[index], onto the front of each sub_solution in sub_solutions, and add each augmented sub_solution to our list of solutions that we return at the end of the function:
solutions.append([array[index]] + sub_solution)
And that's it!

Counting consecutive numbers in a list

I couldn't find a question that was similar enough to mine to where I could develop a satisfactory answer.
I'm pretty new to Python (3.4.3). I am trying to add elements to an output list using a for loop by comparing each element of an input list to the next element in it.
Here is my code so far:
random_list=[1,4,5,6,7,9,19,21,22,23,24]
def count_consec(random_list):
count=1
consec_list=[]
for i in listrand:
if listrand[i] == listrand[i+1]+1:
count+=1
else:
list.append(count)
return consec_list
Basically, I want to add to consec_list[] values that represent how the length of consecutive blocks of numbers in random_list[].
I expect my output in this case to look like this:
[1,4,1,1,4]
As in, there is one singular number, followed by 4 consecutive numbers, followed by one singular number, followed by one singular number, followed by 4 consecutive numbers.
I tried many different ways and I have gotten the function to build a list, but all the elements are 1s.
You could take an approach like this:
def countlist(random_list):
retlist = []
# Avoid IndexError for random_list[i+1]
for i in range(len(random_list) - 1):
# Check if the next number is consecutive
if random_list[i] + 1 == random_list[i+1]:
count += 1
else:
# If it is not append the count and restart counting
retlist.append(count)
count = 1
# Since we stopped the loop one early append the last count
retlist.append(count)
return retlist
There are a few problems with your code, among others undefined variables, or using an element i from the list as the index of that element, but also you will get an index error for the last element, and you never add the last count to the result list.
Instead, I'd suggest using the zip(lst, lst[1:]) recipe for iterating pairs of elements from the list, and using consec[-1] to access and modify the counts already in the list.
def count_consec(lst):
consec = [1]
for x, y in zip(lst, lst[1:]):
if x == y - 1:
consec[-1] += 1
else:
consec.append(1)
return consec
random_list=[1,4,5,6,7,9,19,21,22,23,24]
print(count_consec(random_list))
# [1, 4, 1, 1, 4]
Alternatively, you could subtract the index from each element. This way, successive consecutive elements will end up being the same element. Now, you can just use itertools.groupby to group and count those elements.
>>> random_list=[1,4,5,6,7,9,19,21,22,23,24]
>>> [e-i for i, e in enumerate(random_list)]
[1, 3, 3, 3, 3, 4, 13, 14, 14, 14, 14]
>>> [sum(1 for _ in g) for _, g in itertools.groupby(_)]
[1, 4, 1, 1, 4]
The following code fixes it up. You were iterating over the elements of the list itself instead of the counter you were referencing.
random_list=[1,4,5,6,7,9,19,21,22,23,24]
def count_consec(listrand):
count=1
consec_list=[]
for i in range(len(listrand[:-1])):
if listrand[i]+1 == listrand[i+1]:
count+=1
else:
consec_list.append(count)
count=1
# Account for the last iteration
consec_list.append(count)
return consec_list
print(count_consec(random_list))
Returns this:
[1, 4, 1, 1, 4]
Here's my version
Say you had a list of numbers, which you want to loop through and count the consecutive streaks:
list_of_nums = [4,5,7,8,2,1,3,5,7,6,8,9,9,9,2,2]
You could do something like this:
streak_count = []
counter = 1
for i in range(len(list_of_nums)):
if i != (len(list_of_nums) - 1):
diff = list_of_nums[i+1] - list_of_nums[i]
if diff == 1:
counter += 1
else:
streak_count.append(counter)
counter = 1
else:
streak_count.append(counter)

Recursion code in python

I'm new to python and trying to solve my homework... I'm trying to create a recursion function that takes a list of numbers [a, b, c....] and turns it to this list: [a, a+b, a+b+c, ....].
This is my code:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
new_list=numbers
last=new_list[-1]
if numbers==[]:
return numbers
if len(numbers) == 1:
return numbers[0]
new_list.remove(last)
rec= rec_cumsum(new_list)
new_list.append(rec+last)
return last+rec
this works but because I used return for last+rec, I can't use return to get the list back (new_list). Please explain to me what did I do wrong... thanks!
Let's write some test cases and practice some test-driven development:
tests = [[], # Desired answer: []
[1], # [1]
[1,2], # [1, 3]
[1,2,3], # [1, 3, 6]
[1,2,1,3]] # [1, 3, 4, 7]
for t in tests:
print(rec_cumsum(t))
If we add this to your code and run it, we get:
last=new_list[-1]
IndexError: list index out of range
Why is this? Apparently -1 is an out-of-range index. Why wouldn't new_list have a -1 index?
Aha. That happens if new_list is empty. So we need to address the base case first. While we're at it, let's also use #MartijnPieters' suggestion:
if len(numbers) <= 1:
return numbers
to obtain
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers
last=new_list[-1]
new_list.remove(last)
rec = rec_cumsum(new_list)
new_list.append(rec[-1]+last)
return last+rec
Now run the test again. This time we get
return last+rec
TypeError: unsupported operand type(s) for +: 'int' and 'list'
So now Python is saying last is an int and rec is a list, and we can not add the two together.
Okay, rec should be a list since it is the return value of rec_cumsum(new_list). What should replace last+rec?
Let's think in terms of a concrete example. If rec is [a, a+b] then we want to return [a, a+b, a+b+c]. How do we form a+b+c?
How about adding the last element in rec with the last element of numbers:
rec[-1]+last
We want to append this to the end of rec:
rec.append(rec[-1]+last)
Let's make that change and see what happens. But while we're editing, let's also clean up some code we never use. We can delete new_list.append(rec[-1]+last):
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers
last=new_list[-1]
new_list.remove(last)
rec = rec_cumsum(new_list)
rec.append(rec[-1]+last)
return rec
Now our program returns
[]
[1]
[1, 3]
[1, 3, 6]
[2, 3, 4, 7]
Hurray, our program runs without errors. But wait... it returns the wrong results. Look at the last line.
rec_cumsum([1,2,1,3]) is returning [2,3,4,7] whereas the correct answer is [1,3,4,7]. Why is the first number wrong?
It has to do with new_list.remove(last). This command removes the first occurrence of last from new_list. We want to remove the last occurrence.
So instead, let's use
new_list = numbers[:-1]
So the program becomes:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers[:-1]
last=numbers[-1]
rec = rec_cumsum(new_list)
rec.append(rec[-1]+last)
return rec
Run the tests. It works! Now it is a good practice to look back at our solution and see how it can be tightened up and made more elegant.
I see we used new_list and last as temporary variables. Do we really need them?
def rec_cumsum(numbers):
if len(numbers)<=1:
return numbers
result = rec_cumsum(numbers[:-1])
result.append(result[-1]+numbers[-1])
return result
Your function should always return a list; for the empty list case, an empty list, and for the case where there is only one element, a list with only one element.
But your code returns the one element, not a list with one element:
if len(numbers) == 1:
return numbers[0]
Change that to returning just numbers:
if len(numbers) == 1:
return numbers
You can combine this with the other end-state test:
if len(numbers) < 2:
return numbers
Next problem is that you are not creating a copy of a list when you create the variable new_list; you create a reference to the same list, you'd have to use a slice or create an explicit new list:
new_list = numbers[:]
If you are going to remove a value from that list anyway, you may as well adjust the slice a little, and put this after testing numbers (why do the work otherwise):
if len(numbers) < 2:
return numbers
new_list = numbers[:-1]
last = numbers[-1]
Nowhere in your code do you actually compute a sum; nothing is added to your numbers. You never add a to b, c, etc. Moreover, you seem to be focusing on the last number, while your assignment states you needed to sum the first value to the rest of the list.
And there is a pattern there. Not only do you add a to b, but the sum of a + b is added to c, and that sum is then added to d, etc. Let's make use of that:
def rec_cumsum(numbers, culmulated_sum=0):
if len(numbers) < 1:
return numbers
sum = numbers[0] + culmulated_sum
return [sum] + rec_cumsum(numbers[1:], sum)
Note that I don't even bother storing a copy of numbers now; may as well just pass it to the next recursion as a slice of everything but the first element. We also use the first element from numbers to create our sum (numbers[0]).
Also, we now pass along the culmulative sum so far, starting at 0; and that means we need to change the end condition of the recursive function; we are essentially adding [0] to the start of the list, and we want to make sure we sum that with the next element always.
This now does what you need:
>>> rec_cumsum([5, 1, 10, 2, 3])
[5, 6, 16, 18, 21]

Categories