I am trying to use recursion on a nested list. Here I am trying to get the innermost element.
input_list = [1,2,3,4,[5,6,7,[8,9,[10]]]]
list1 = input_list
def sublist1(list, sublist=[]):
if len(list) == 0:
return sublist
else:
sublist.append(list)
sublist1(list[1:], sublist)
print(sublist)
sublist1(list1)
The output I am getting is this:
[[1, 2, 3, 4, [5, 6, 7, [8, 9, [10]]]], [2, 3, 4, [5, 6, 7, [8, 9, [10]]]], [3, 4, [5, 6, 7, [8, 9, [10]]]], [4, [5, 6, 7, [8, 9, [10]]]], [[5, 6, 7, [8, 9, [10]]]]]
I tried changing the index but it's not giving me the expected output [10].
Any help would be appreciated.
You can make a recursive call only if any item in the current given list is a list; otherwise it means the current list is already the innermost list, so you can return the list as is:
def inner_most(lst):
for i in lst:
if isinstance(i, list):
return inner_most(i)
return lst
input_list = [1,2,3,4,[5,6,7,[8,9,[10]]]]
print(inner_most(input_list))
This outputs:
[10]
Demo: https://replit.com/#blhsing/SwelteringFlakyDividend
This will answer your nested travels
input_list = [1,2,3,4,[5,6,7,[8,9,[10]]]]
list1 = input_list
def sublist1(list):
if(len(list) > 1):
for l in list:
#print(l)
# print(type(l))
if type(l) == type([]) :
return sublist1(l)
else:
continue
return list
print(sublist1(list1))
print(list1[-1][-1][-1])
This would get you [10]
Note: I know there is probably an answer for this on StackOverflow already, I just can't find it.
I need to do this:
>>> lst = [1, 2, 3, 4, 5, 6]
>>> first_two = lst.magic_pop(2)
>>> first_two
[1, 2]
>>> lst
[3, 4, 5, 6]
Now magic_pop doesn't exist, I used it just to show an example of what I need. Is there a method like magic_pop that would help me to do everything in a pythonic way?
Do it in two steps. Use a slice to get the first two elements, then remove that slice from the list.
first_list = lst[:2]
del lst[:2]
If you want a one-liner, you can wrap it in a function.
def splice(lst, start = 0, end = None):
if end is None:
end = len(lst)
partial = lst[start:end]
del lst[start:end]
return partial
first_list = splice(lst, end = 2)
One option would be using slices
def func(lst: list, n: int) -> tuple:
return lst[:n], lst[n:]
lst = [1, 2, 3, 4, 5, 6]
first_two, lst = func(lst, 2)
print(lst)
# [3, 4, 5, 6]
Alternative, here is a kafkaesque approach using builtins:
def func(lst: list, i: int) -> list:
return list(map(lambda _: lst.pop(0), range(i)))
lst = list(range(10))
first_two = func(lst, 2)
print(first_two)
# [0, 1]
print(lst)
# [2, 3, 4, 5, 6, 7, 8, 9]
Try:
lst = [1, 2, 3, 4, 5, 6]
first_two, lst = lst[:2], lst[2:]
print(first_two)
print(lst)
Prints:
[1, 2]
[3, 4, 5, 6]
You can just create a lambda function to do this.
magic_pop = lambda x,y:(x[:y],x[y:]) if y<len(lst) else x
magic_pop(lst,3)
Out[8]: ([1, 2, 3], [4, 5, 6])
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.
I am writing code about two lists and the sum element without using the sum function. So I need to return the sum of its elements. How do I define a list c with the total number of list a and b
The code below is what I already tried.
def add(list_a, list_b):
list_a = [1, 2, 3, 4, 5]
list_b = [1, 2, 3, 4, 5]
list_c = []
for i in range (0,5):
list_c.append(list_a[i]+second[i])
print (list_c)
The error code:
File "sum.py", line 7, in
list_c.append(list_a[i]+second[i])
NameError: name 'list_c' is not defined
You have an indentation problem. It should work if you indent the for block and the print statement. You also have a typo, second[i] should be list_b[i].
def add(list_a, list_b):
list_c = []
for i in range(0,5):
list_c.append(list_a[i]+list_b[i])
return(list_c)
list_a = [1, 2, 3, 4, 5]
list_b = [1, 2, 3, 4, 5]
print(add(list_a, list_b))
# [2, 4, 6, 8, 10]
A really short way to write this would be:
print([x+y for x,y in zip(list_a, list_b)])
It only works when the lists have the same length.
There are two issues. First, you don't need to define your lists inside a function, and secondly you were referencing the second list as second instead of list_b. The below is all you need:
list_a = [1, 2, 3, 4, 5]
list_b = [1, 2, 3, 4, 5]
list_c = []
for i in range(0, 5):
list_c.append(list_a[i] + list_b[i])
print (list_c)
Alternatively if you want to use it as a reusable function then you can move your loop logic into the function itself and pass the lists as parameters:
def add(list_a, list_b):
summed_list = []
for i in range(0, 5):
summed_list.append(list_a[i] + list_b[i])
return summed_list
summed = add([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
print(summed)
You might use map in order to achieve that following way:
list_a = [1, 2, 3, 4, 5]
list_b = [1, 2, 3, 4, 5]
def add(a,b):
return list(map(lambda x,y:x+y,list_a,list_b))
print(add(list_a,list_b))
Output:
[2, 4, 6, 8, 10]
I'm trying to design a code that will reverse a given list at the index of a given value. The rest of the list beyond the value will be printed in correct order, but I can't seem to complete it.
This is the code I have so far.
def reverse(my_list, value):
lst = []
lst2 = []
for x in range(my_list[0], my_list[value]):
x = my_list[x]
lst2.append(x)
for i in range(len(lst2)-1, -1, -1):
x = lst2[i]
lst.append(x)
for x in range(my_list[value], len(my_list)):
x = my_list[x]
lst.append(x)
print(lst)
If the input is this.
reverse([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5)
The output should be.
[5, 4, 3, 2, 1, 6, 7, 8, 9, 10]
But instead the output is this.
[6, 5, 4, 3, 2, 7, 8, 9, 10]
Can anyone help me to determine how to get the needed output?
It would be much easier to implement with slicing:
def reverse(my_list, value):
return my_list[:value][::-1] + my_list[value::]
Indexes in first and third cycles are wrong, you have to iterate through indexes not values. Write like here:
def reverse(my_list, value):
lst = []
lst2 = []
for x in range(0, value):
x = my_list[x]
lst2.append(x)
for i in range(len(lst2)-1, -1, -1):
x = lst2[i]
lst.append(x)
for x in range(value, len(my_list)):
x = my_list[x]
lst.append(x)
print(lst)
reverse([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5)
output: [5, 4, 3, 2, 1, 6, 7, 8, 9, 10]