How to add a counter to a recursive function? [Python] - python

The program has to replace two numbers within the list with a number that is also given in the parameters. I can't change the parameters, but I can create other functions also. In addition I must use recursion. So far I figured out how to do the replacement with recursion, but I'm confused about the count. Every time I try I cant seem to only replace the first two occurrences of 'x' with 'y', instead I always get to replace every 'x' with 'y'.
EDIT: And I can't use global variables.
def replaceFirstTwo(x,y,lst):
if lst == []:
return []
else:
if lst[0] == x:
return [y] + replaceFirstTwo(x,y,lst[1:])
else:
return [lst[0]]+ replaceFirstTwo(x,y,lst[1:])
A correct outcome should look like this :
replaceFirstTwo(1,2,[5,1,2,3,1,1])
[5, 2, 2, 3, 2, 1]

If x is only ever going to be positive then you can use, the negative version to signify that it is the second time that you are running the function. Before changing x to something to signify do nothing.
I have modified your function so it does this, however it will not work with negative values of x as the abs(x) will make it positive.
def replaceFirstTwo(x,y,lst):
if lst == []:
return []
else:
if x is not None:
if lst[0] == abs(x):
if x > -1:
x = -x
else:
x = None
return [y] + replaceFirstTwo(x,y,lst[1:])
else:
return [lst[0]]+ replaceFirstTwo(x,y,lst[1:])
else:
return [lst[0]]+ replaceFirstTwo(x,y,lst[1:])

Here's an alternative using an inner function, which has no restrictions such as the accepted solution:
def replaceFirstTwo(x, y, lst):
def sub(lst, res, count):
if lst:
e = lst[0]
if e == x and count < 2:
return sub(lst[1:], res+[y], count + 1)
else:
return sub(lst[1:], res+[e], count)
else:
return res
return sub(lst, [], 0)

Related

Loop. Why it can see only 10 from whole list?

def new_list(lst):
for i in lst:
if i%10 == 0:
return i
else:
return False
print(new_list([10, 20.0, 25, 30, 40, 98]))
i want to see all numbers from the list that can be divided into 10
Calling return in a function ends execution of the function. So either way, the your function will stop running after the first iteration in your for loop. I don't know what you are expecting for output, but in your function you can instead append the items to a list and return the list at the end:
def new_list(lst):
result_list = []
for i in lst:
if i%10 == 0:
result_list.append(i)
return result_list
This can also be done with a list comprehension:
def new_list(lst):
return [x for x in lst if x % 10 == 0]

How to use recursion in Python to negate the last occurrence of a specific element of a list?

I need a function negate_last(n, values) that takes an integer input of n and an arbitrary list of integers values and uses recursion to negate the last occurrence of n. I have tried to code the following lines, but the function returns the list with all of the element n in the list negated. How could I fix this function in order for it to only return the last occurrence of n in the list?
def negate_last(n, values):
""" takes as inputs an integer n and an arbitrary list of integers values and that uses recursion to create and return a version of values in which only the last occurrence of n (if any) has been negated. """
if values == []:
return []
else:
rest_part = negate_last(n, values[1:])
if values[0] == n:
result = [-1 * values[0]] + rest_part
return result
else:
return [values[0]] + rest_part
'''
The below code should negate the last occurrence of n in the given array.
I think the issue in your code is that you are calling the recursive call for all non empty array which is negating all the occurrences of n. Instead if we find an occurrence (checking from right to get the last occurrence), we should treat that as a base case as we don't want to negate any more occurrences.
def negate_last(n, arr):
if not arr:
return []
if arr[-1] == n:
arr[-1] = -arr[-1]
return arr
return negate_last(n, arr[:-1]) + [arr[-1]]
print(negate_last(5, [1, 2, 5, 4, 5]))
I am not sure if this was a solution, but what I so was to add a variable for validation outside the function and once the variable change to 1, then the next time a n appears it will not change. Hope it helps
validation = 0
def negate_last(n, values):
if values == []:
return []
else:
rest_part = negate_last(n, values[1:])
if values[0] == n:
if validation == 0:
result = [-1 * values[0]] + rest_part
validation = 1
return result
else:
return [values[0]] + rest_part
else:
return [values[0]] + rest_part

Summation of values in nested lists

I have encountered a problem where a return gives None back, though the variable had a value just a single line of code before.
mylist = [[7]]
def sumcalc(the_list,n):
s = n
for x,y in enumerate(the_list):
if type(y) == list:
sumcalc(y,s)
elif type(y) == int:
s += y
if x < len(the_list)-1:
sumcalc(the_list[x+1], s)
else:
print (s)
return s
print(sumcalc(mylist,0))
The print command in the second to last line gives me 7, as expected. But the return is None. Any help on this would be appreciated :)
If you are writing a recursive function. You must put return key word before recursive call.
mylist = [[7]]
def sumcalc(the_list,n):
s = n
for x,y in enumerate(the_list):
if type(y) == list:
return sumcalc(y,s)
elif type(y) == int:
s += y
if x < len(the_list)-1:
sumcalc(the_list[x+1], s)
else:
print (s)
return s
print(sumcalc(mylist,0))
sumcalc() doesn't do anything on its own; you need to use the return value. Beyond this, the index checking is unecessary, as the return could simply be placed after the loop. Here is a simpler way of writing the nested sum code.
def nested_sum(x):
if type(x)==int:
return x
if type(x)==list:
return sum(
nested_sum(item)
for item in x
)

remove negative element from nested list and square the list without using loop

Input: testlist = [[1,2,3,-1],2,3,[3,-4,1,3],-1,-3]
Requirement:
remove elements less than zero
then square the elements without using any loop
output :
[[1,4,9],4,9,[9,1,9]]
def testlist(f, l):
def listelement(inside):
return testlist(f, inside) if type(inside) is list else f(inside)
return list(map(listelement, l))
def square(x):
return x * x
def square_list(l):
return testlist(square, l)
You could think about the problem recursively:
If the list is empty, return an empty ist
If it isn't, for the first item of the list:
If it's a negative number, omit it
If it's a non-negative number, square it
If it's a list, apply the function on it.
Return a list that's a concatenation of the element from #1 and the function applied to the rest of the list.
Or, in python:
def func(l):
if len(l) == 0:
return []
item = l[0]
if isinstance(item, list):
result = [func(item)]
elif item >= 0:
result = [item**2]
else:
result = []
return result + func(l[1:])
Instead of having two separate functions, you can do the squaring and the checking for positive in the same function.
To handle not looping we can use recursion. Since we are already using recursion, we can handle lists with the same recursive function.
test_list = [[1,2,3,-1],2,3,[3,-4,1,3],-1,-3]
def positive_square_list(lst, index):
if index < len(lst):
if type(lst[index]) == list:
positive_square_list(lst[index], 0)
index += 1
if lst[index] < 0:
lst.pop(index)
index -= 1
if index == len(lst):
return lst
else:
return positive_square_list(lst, index+1)
lst[index] = lst[index] ** 2
return positive_square_list(lst, index+1)
return lst
output = positive_square_list(test_list, 0)
The variable output will have the values: [[1,4,9],4,9,[9,1,9]]

I am trying to make a function which return max from nested list?

I wrote this and its working fine with everything but when I have an empty list
in a given list(given_list=[[],1,2,3]) it saying index is out of range. Any help?
def r_max (given_list):
largest = given_list[0]
while type(largest) == type([]):
largest = largest[0]
for element in given_list:
if type(element) == type([]):
max_of_elem = r_max(element)
if largest < max_of_elem:
largest = max_of_elem
else: # element is not a list
if largest < element:
largest = element
return largest
You are assuming given_list has at least 1 element which is incorrect.
To avoid index out of range, you may add
if (len(given_list) == 0)
return None
to the beginning of your function.
that error indicates your index is out of range, which is the case with the first element of your example. The solution is not to iterate over lists of length zero:
def r_max (given_list):
largest = given_list[0]
while type(largest) == type([]):
largest = largest[0]
for element in given_list:
if type(element) == type([]):
# If the list is empty, skip
if(len(elemnt) == 0)
next
max_of_elem = r_max(element)
if largest < max_of_elem:
largest = max_of_elem
else: # element is not a list
if largest < element:
largest = element
return larges
while your at it, you might want to assert len(given_list)>0 or something equivalent.
If the nesting is arbitrarily deep, you first need recursion to untangle it:
def items(x):
if isinstance(x, list):
for it in x:
for y in items(it): yield y
else: yield x
Now, max(items(whatever)) will work fine.
In recent releases of Python 3 you can make this more elegant by changing
for it in x:
for y in items(x): yield y
into:
for it in x: yield from it
If you're confident that there will only be one level of nesting in there, you could do something like
def r_max(lst):
new_lst = []
for i in lst:
try:
new_lst.extend(i)
except TypeError:
new_lst + [i]
return max(new_lst)
But I'm not in love with that solution - but it might inspire you to come up with something nicer.
Two things I'd like to highlight about this solution, in contrast to yours:
All the type-checking you're doing (type(largest) == type([]), etc.) isn't considered idiomatic Python. It works, but one of the key points of Python is that it promotes duck typing/EAFP, which means that you should be more concerned with what an object can do (as opposed to what type it is), and that you should just try stuff and recover as opposed to figuring out if you can do it.
Python has a perfectly good "find the largest number in a list" function - max. If you can make your input a non-nested list, then max does the rest for you.
This will find the maximum in a list which contains nested lists and ignore string instances.
A = [2, 4, 6, 8, [[11, 585, "tu"], 100, [9, 7]], 5, 3, "ccc", 1]
def M(L):
# If list is empty, return nothing
if len(L) == 0:
return
# If the list size is one, it could be one element or a list
if len(L) == 1:
# If it's a list, get the maximum out of it
if isinstance(L[0], list):
return M(L[0])
# If it's a string, ignore it
if isinstance(L[0], str):
return
# Else return the value
else:
return L[0]
# If the list has more elements, find the maximum
else:
return max(M(L[:1]), M(L[1:]))
print A
print M(A)
Padmal's BLOG
I assume that the max element of an empty list is negative infinity.
This assumption will deal with the cases like [], [1,2,[],5,4,[]]
def find_max(L):
if len(L) == 0:
return float("-inf")
elif len(L) == 1:
if isinstance(L[0], list):
return find_max(L[0])
else:
return L[0]
elif len(L) == 2:
if isinstance(L[0], list):
firstMax = find_max(L[0])
else:
firstMax = L[0]
if isinstance(L[1], list):
lastMax = find_max(L[1])
else:
lastMax = L[1]
if firstMax > lastMax:
return firstMax
else:
return lastMax
else:
if isinstance(L[0], list):
firstMax = find_max(L[0])
lastMax = find_max(L[1:])
if firstMax > lastMax:
return firstMax
else:
return lastMax
else:
lastMax = find_max(L[1:])
if L[0] > lastMax:
return L[0]
else:
return lastMax

Categories

Resources