Sum of nested list without using SUM function (exercise) - python

Trying to write a function that take the sum of each list and return individual values in a new single list.
E.g
[[2, 7, 6], [9, 5, 1], [4, 3, 8]]
becomes
[15, 15, 15]
What I have so far:
def row_sums(square):
total_list = []
total = 0
for i in square:
for j in i:
total += j
total_list.append(total)
return total_list
But this just accumulates each list onto each other resulting in:
[15, 30, 45]
I'm not sure how to keep the sums for each list separate here. The SUM function is not allowed here as it's an exercise on nested loops.
Thanks.

You need to reset your total counter before starting each inside for.
Also, you don't need to declare it outside, because you will use it only inside.
def row_sums(square):
total_list = []
for i in square:
total = 0
for j in i:
total += j
total_list.append(total)
return total_list

The error is you do not re-initialize the total variable after each loop. Instead, initialize sum = 0 inside he first for-loop like so:
def row_sums(square):
total_list = []
for i in square:
total = 0
for j in i:
total += j
total_list.append(total)
return total_list

Just for fun:
>>> list = [[2, 7, 6], [9, 5, 1], [4, 3, 8]]
>>> import functools
>>> [functools.reduce(lambda x, y: x + y, sublist, 0) for sublist in list]
[15, 15, 15]
I did't use sum :)
You can read more about functools.reduce here.
Edit: As Sevanteri pointed out in the comment, you can also use [functools.reduce(int.__add__, sublist, 0) for sublist in list]
(if you really want to drive your teacher mad!)

You need to zero your total for each list.
def row_sums(square):
total_list = []
total = 0
for i in square:
for j in i:
total += j
total_list.append(total)
total = 0
return total_list

To be different, flatten the lists and using a generator (assumes sublists are the same length):
def _notsum2(lists):
per_yield = len(lists)
total = 0
for ind, next in enumerate(val for sublist in lists for val in sublist):
if ind % per_yield == 0 and ind:
yield total
total = 0
total += next
yield total
if __name__ == '__main__':
li = [[2, 7, 6], [9, 5, 1], [4, 3, 8]]
print [g for g in _notsum2(li)]

You can also do it using map and list comprehension as:
l=[[2, 7, 6], [9, 5, 1], [4, 3, 8]]
a,b,c=[x for x in l]
map(lambda x,y,z:x+y+z, a,b,c)

[sum(i) for i in zip(*[[2, 7, 6], [9, 5, 1], [4, 3, 8]])]
bultin zip func is what you exactly needed

Related

Add previous value and carry the result in a list

In Python, I am trying to add the to each number in a list, the value of the previous number and carry this sum through all of the list.
Given numbers = [2, 5, 3, 2], the output should be [2, 7, 10, 12], adding and carrying the sum until the end.
The following code is the one closest to the solution I managed to be, but I am getting [0, 2, 7, 10, 12], since I am starting with zero, but cannot find a different solution.
numbers = [2, 5, 3, 2]
newList = [0]
sumN = 0
for n in range(0, len(numbers)):
sumN += numbers[n]
newList.append(sumN)
print(newList)
Any help is appreciated.
Try this:
new_list = []
for i in range(len(numbers)):
new_list.append(numbers[i] + sum(numbers[:i]))

Python: Remove values that are duplicated in the previous list inside a nested list

Example of a given nested list:
nList = [[2,5,99,99],[-3,8,1,2,10],[1, 7,100,10]]
Expectations: Remove values that are duplicated in the previous list.
Expected Output:
oList = [[2, 5, 99], [-3, 8, 1, 10], [7, 100]]
My Codes:
def RemoveDup(nList):
lst = []
for i in nList:
for j in i:
if j not in lst:
lst.append(j)
return lst
>>> print(RemoveDup([[2,5,99,99],[-3,8,1,2,10],[1, 7,100,10]]))
>>> [2, 5, 99, -3, 8, 1, 10, 7, 100]
I still couldn't figure out how to make the output a nested list like the expected output, any help and advice are appreciated!
As there is no "previous" element to compare against the first element in the nested list then it must be dealt with as is.
This may achieve the real objective:
nList = [[2,5,99,99],[-3,8,1,2,10],[1, 7,100,10]]
output = [nList[0]]
for e in nList[1:]:
t = []
for x in e:
if x not in output[-1]:
t.append(x)
output.append(t)
print(output)
Output:
[[2, 5, 99, 99], [-3, 8, 1, 10], [7, 100]]
If duplicates need to be removed from the first element in the list then:
nList = [[2,5,99,99],[-3,8,1,2,10],[1, 7,100,10]]
output = []
t = []
for e in nList[0]:
if e not in t:
t.append(e)
output.append(t)
for e in nList[1:]:
t = []
for x in e:
if x not in output[-1]:
t.append(x)
output.append(t)
print(output)
Output:
[[2, 5, 99], [-3, 8, 1, 10], [7, 100]]
Note:
The temptation to use sets should be avoided as the order of the output list may not be as expected
Using this solution you don't even need to make an auxiliary list. It deletes the duplicates in place while the function iterates through the numbers.
This is a much more efficient as it saves the time of building another data structure and saves the space necessary for filling up another nested list for the solution.
nList = [[2,5,99,99],[-3,8,1,2,10],[1, 7,100,10]]
def RemoveDup(nList):
j = len(nList) - 1 # size of list
while j >= 0: # iterate through sublists
k = len(nList[j]) - 1 # size of sublist
while k >= 0: # iterate through each number
if j - 1 < 0: # check if there are any lists before position
# if not then check the current list for duplicates
if nList[j][k] in nList[j][:k]:
del nList[j][k] # if there is a duplicate delete it
# if there is a list before the current position check if
# it contains the current number
elif nList[j][k] in nList[j-1]:
del nList[j][k] # if it does delete it
k -= 1
j -= 1
RemoveDup(nList)
print(nList)
OUTPUT
[[2, 5, 99], [-3, 8, 1, 10], [7, 100]]
Code:
def RemoveDup(nList):
tmp = list(chain.from_iterable(nList)) #Converting nested list to list
dup = list(set([x for x in tmp if tmp.count(x) > 1])) #finding the duplicates
for i in reversed(nList): #we have reverse the loop so
for j in i: # we can keep first and remove second duplicate
if j in dup:
dup.remove(j) #emptying the dup list as
i.remove(j) # we are deleting the duplicate values
return nList
RemoveDup(nList)
Output:
[[2, 5, 99], [-3, 8, 1, 10], [7, 100]]
You need to add two intermediate containers
nList = [[2, 5, 99, 99], [-3, 8, 1, 2, 10], [1, 7, 100, 10]]
def RemoveDup(nList):
aggregation = []
vessel2 = []
for i in nList:
lst = []
for j in i:
if j not in aggregation:
lst.append(j)
aggregation.append(j)
vessel2.append(lst)
return vessel2
print(RemoveDup(nList))

Function which takes an integer k that checks if a list of integer lists l, returns the count of the number of integer lists in l, which sum to k

For example: sumToK(10,[[1,2],[1,2,3,4],[5,5,0],[8,2,3],[-15,25]]) returns 3 since 3 of the inner 5 lists in the given list sum exactly to 10. I can use the sum function, and other functions such as max, min, len. I need to do this with code using a while loop and code using a for loop.
So far I have this for the for loop but lost on the while loop:
def sumTotal(k, l):
count = 0
for x in l:
count += x
return count
The problem for me is checking for multiple lists and counting how many add up to k
Version with while loop as you asked in the post
Modifies initial list:
def sumTotal(k, l):
ans = 0
while l:
curr = l.pop()
if sum(curr) == k:
ans += 1
return ans
ans = sumTotal(10, [[1, 2], [1, 2, 3, 4], [5, 5, 0], [8, 2, 3], [-15, 25]])
print(ans) # outputs 3
Does not modify initial list:
def sumTotal(k, l):
ans = 0
idx = 0
while idx < len(l):
if sum(l[idx]) == k:
ans += 1
idx += 1
return ans
ans = sumTotal(10, [[1, 2], [1, 2, 3, 4], [5, 5, 0], [8, 2, 3], [-15, 25]])
print(ans) # outputs 3
Update
I added a recursion solution but honestly it's not the type of the task, which you want to solve recursively. Recursion takes O(n) space, which is unnecessary there.
def sumTotal(k, l, index = 0):
if index == len(l):
return 0
else:
return sumTotal(k, l, index + 1) + (1 if sum(l[index]) == k else 0)
ans = sumTotal(10, [[1, 2], [1, 2, 3, 4], [5, 5, 0], [8, 2, 3], [-15, 25]])
print(ans) # outputs 3

Python sum in list consists of integers and other lists and nested lists

I have problem with a function that returns a sum of values in list given as argument. But this list can consists of integers and other lists, but this lists can have other lists etc etc
like in example:
[10, 5, [1, [5, 4, 3]], 9, [1, 1, [2, 3]]] => 44
You can flatten the list and then sum it:
lst = [10, 5, [1, [5, 4, 3]], 9, [1, 1, [2, 3]]]
def flatten(l):
if isinstance(l, list):
for v in l:
yield from flatten(v)
else:
yield l
out = sum(flatten(lst))
print(out)
Prints:
44
You could also write a recursive function that does the summation:
def my_sum(x):
value = 0
for i in x:
if not isinstance(i, list):
value += i
else:
value += my_sum(i)
return value
my_sum(lst)
44
Using a recursive function should work :
def your_function(embeded_list):
n = len(embeded_list)
sum = 0
for i in range(n) :
if len(embeded_list[i]) == 1 :
sum+=embeded_list[i]
else :
sum+=your_function(embeded_list[i])
return(sum)

How to deal with this exercise using recursion in Python?

I am struggling to solve an exercise regarding lists in Python. The exercise says:
Write a function that takes a list containing numbers and lists of
numbers inside them, reverses it (including the lists of numbers
inside the main list) using recursion.
Afterwards, the function should return a tuple containing three
elements. The first element represents the amount of all the numbers
present in the list (including the ones in the sublists), the second
element is the sum of all the numbers (also the ones inside the
sublists), and the third element is a sorted list of all the integers.
Again we should use recursion.
I managed to reverse the whole list using two functions, but when it comes to accessing the numbers inside the sublists to use them for the tuple, I really don't know what to do.
Here you can have a look at the list of lists:
lista = [3, 3, 5, [[1, 8, [9, 3]], 3, [2, [9, [5, 6],[9]] ] ]]
Here you can check my code:
def exercise (lista):
lista_ordinata = []
count = 0
somma = 0
reverse_list(lista)
for x,y in enumerate(lista):
if isinstance (x,(int)):
count += 1
else:
count = 0
for num in lista:
if isinstance(num,(int)):
somma += num
for i in lista:
if isinstance(i,int):
lista_ordinata.append(i)
return (count,somma,lista_ordinata)
def is_list (lista):
return isinstance(lista,list)
def reverse_list(lista):
lista_nuova = lista[::-1]
for x,y in enumerate(lista_nuova):
if is_list(y):
lista_nuova[x] = reverse_list(y)
lista.clear()
lista.extend(lista_nuova)
return lista
Here you can see the expected list which I reversed:
lista = [[[[[9], [6, 5], 9], 2], 3, [[3, 9], 8, 1]], 5, 3, 3]
The function must return the following tuple:
(13,66, [1,2,3,5,6,8,9])
The output I get is incorrect:
(4, 11, [5, 3, 3])
The first element should be the counting of all the numbers, and not just the numbers outside the sublists, The sum is also incorrect, The list is not outputting all the numbers.
What should I do? Keep in mind that the "exercise" function should use recursion.
You are using recursion just fine in the reverse function, just use recursion in you exercise function:
def exercise(lista):
lista_ordinata = []
count = 0
somma = 0
# reverse_list(lista)
for x in lista:
if isinstance(x, list):
recursion = exercise(x) # call recursion until you have a list with only integers
# and add the result to your running totals
count += recursion[0]
somma += recursion[1]
lista_ordinata.extend(recursion[2])
else:
count += 1
somma += x
lista_ordinata.append(x)
lista_ordinata = sorted(list(set(lista_ordinata)))
return count, somma, lista_ordinata
print(exercise(lista))
(13, 66, [1, 2, 3, 5, 6, 8, 9])
def exercise(a, polish=sorted):
if not isinstance(a, list):
return 1, a, {a}
a.reverse()
amount, sum, numbers = 0, 0, set()
for b in a:
a, s, n = exercise(b, set)
amount += a
sum += s
numbers |= n
return amount, sum, polish(numbers)
Or with a little helper doing the reversals and collecting the numbers:
def exercise(a):
def go(a):
if isinstance(a, list):
a.reverse()
for b in a:
go(b)
else:
numbers.append(a)
numbers = []
go(a)
return len(numbers), sum(numbers), sorted(set(numbers))
Demo:
lista = [3, 3, 5, [[1, 8, [9, 3]], 3, [2, [9, [5, 6],[9]] ] ]]
>>> exercise(lista)
(13, 66, [1, 2, 3, 5, 6, 8, 9])
>>> lista
[[[[[9], [6, 5], 9], 2], 3, [[3, 9], 8, 1]], 5, 3, 3]
Here's a way without any loops at all.
First of all, we can have a definition for a partial insertion sort, which inserts any value to its correct position in an existing sorted array.
def partialInsertionSort(val, idx, sortarr):
if idx == len(sortarr):
sortarr.append(val)
elif val < sortarr[idx]:
sortarr.insert(idx, val)
elif val > sortarr[idx]:
sortarr = partialInsertionSort(val, idx+1, sortarr)
return sortarr
As you travel through any list a, unless you've reached the end of a, there are two possibilities:
The current item is another list -> Recurse through the sublist!
The current item is a digit -> Increment total and count. If this digit is a previously unseen digit, 'insert' it to your list of sorted digits.
Done with the above two possible options, you have thus processed the current element, and can move to the next element by incrementing the index i.
def reverse_and_sort(a, i, out, sortarr, total, count):
if i==len(a):
return out, sortarr, total, count
if isinstance(a[i], list):
a[i], sortarr, total, count = reverse_and_sort(a[i], 0, [], sortarr, total, count)
else:
total += a[i]
count += 1
if a[i] not in sortarr:
sortarr = partialInsertionSort(a[i], 0, sortarr)
out.insert(0, a[i])
return reverse_and_sort(a, i+1, out, sortarr, total, count)
Test:
rev, srt, total, count = reverse_and_sort(lista, 0, [], [], 0, 0)
print(rev) #[[[[[9], [6, 5], 9], 2], 3, [[3, 9], 8, 1]], 5, 3, 3]
print(srt) #[1, 2, 3, 5, 6, 8, 9]
print(total) #66
print(count) #13
A relatively short version, which uses the add operator is given by that:
from operator import add
def sorter(l):
if isinstance(l, list):
temp = [0, 0, []]
for e in map(sorter, l):
temp = list(map(add, e, temp))
return temp[0], temp[1], sorted(set(temp[2]))
return 1, l, [l]
It should give the correct result:
test_list = [[[[[9], [6, 5], 9], 2], 3, [[3, 9], 8, 1]], 5, 3, 3]
sorter(test_list)
>>> (13, 66, [1, 2, 3, 5, 6, 8, 9])
Two liner approach!
Here is a simple solution to the problem, using indirect recursion. Indirect recursion is where a function f(x) calls a function g(x) which in turn calls f(x).
If your problem was just the first part, the solution is just a simple 2 liner -
f = lambda x: [g(i) for i in reversed(x)]
g = lambda x: f(x) if type(x)==list else x
f(lista)
[[[[[9], [6, 5], 9], 2], 3, [[3, 9], 8, 1]], 5, 3, 3]
Beautiful right?
The main idea here is that at an element level you just need to check if the element is an integer and return it, else you need to use another function that lets you iterate over the list. You can have counters at the level of the second function which lets you track the sum and the count and return it with the final function call.
Since you also have the 2nd part to the solution which is using a few counters, you can modify the above code for g(x) to incorporate that as below -
cnt = []
sm = []
#function to iterate over a reversed list
f = lambda x: [g(i) for i in reversed(x)]
#function to call f if list else updated counters and return element
def g(x):
if type(x)==list:
return f(x)
else:
cnt.append(1) #ONLY MODIFICATION
sm.append(x) #ONLY MODIFICATION
return x
#call f and return sum of counters
def rec(l):
o = f(l)
return o, (sum(cnt), sum(sm), sorted(sm))
out, tup = rec(lista)
print(out)
print(tup)
[[[[[9], [6, 5], 9], 2], 3, [[3, 9], 8, 1]], 5, 3, 3]
(13, 66, [1, 2, 3, 3, 3, 3, 5, 5, 6, 8, 9, 9, 9])
def exercise(lista, total = 0, count = 0, all_int = []):
for item in lista:
if isinstance(item, list):
count, total, all_int = exercise(item, total, count, all_int)
elif isinstance(item, int):
total += item
count += 1
if item not in all_int:
all_int.append(item)
all_int.sort()
lista.reverse()
return count, total, all_int
Maybe this would help :)
def exercise (lista):
reverse_list(lista)
r = count_numbers(lista), sum_numbers(lista), sorted(pull_out(lista))
return r
def is_list (lista):
return isinstance(lista,list)
def reverse_list(lista):
lista_nuova = []
for e in lista[::-1]:
if is_list(e):
lista_nuova.append(reverse_list(e))
else:
lista_nuova.append(e)
return lista_nuova
def count_numbers(lista):
c = 0
for e in lista:
if is_list(e):
c += count_numbers(e)
else:
c+=1
return c
def sum_numbers(lista):
s = 0
for e in lista:
if is_list(e):
s += sum_numbers(e)
else:
s+=e
return s
def pull_out(lista):
b_lista = []
for e in lista:
if is_list(e):
b_lista.extend(pull_out(e))
else:
b_lista.append(e)
return b_lista
lista = [3, 3, 5, [[1, 8, [9, 3]], 3, [2, [9, [5, 6],[9]] ] ]]
r = exercise(lista)
print(r)
# (13, 66, [1, 2, 3, 3, 3, 3, 5, 5, 6, 8, 9, 9, 9])
I did it with separate functions for clarity.

Categories