Python recursion in appending lists - python

I want to append to a list recursively but I cannot come up with a function that works. The function takes two arguments times and data. times should be the number of times to append the data.
Here is my code so far:
def replicate_recur(times, data):
result2 = []
if times == 0:
result2.append(data)
else:
result2.append(data)
replicate_recur(times - 1, data)
return result2

You could use a intermediate list to append to in each recursive call. That avoids these redefinition problems you're encountering currently:
def replicate_recur(times, data, result=None):
if result is None: # create a new result if no intermediate was given
result = []
if times == 1:
result.append(data)
else:
result.append(data)
replicate_recur(times - 1, data, result) # also pass in the "result"
return result
When called:
>>> replicate_recur(4, 2)
[2, 2, 2, 2]

To make your code work, you need to extend the list in the current execution with the output of the next recursive call. Also, the lowest depth of the recursion should be defined by times = 1:
def replicate_recur(times, data):
result2 = []
if times == 1:
result2.append(data)
else:
result2.append(data)
result2.extend(replicate_recur(times - 1, data))
return result2
On another note, you can simply replicate your list with:
def replicate(times, data):
return [data]*times

You can use xrange for this, there is no point to use recursion unless it is a coding test.
def replicate(times, data):
result2 = []
for i in xrange(times):
result2.append(data)
return result2
Same function can be written in a recursive way like this:
def replicate_recur(times, data, listTest=None):
# If a list has not been passed as argument create an empty one
if(listTest == None):
listTest = []
# Return the list if we need to replicate 0 more times
if times == 0:
return listTest
# If we reach here at least we have to replicate once
listTest.append(data)
# Recursive call to replicate more times, if needed and return the result
replicate_recur(times-1, data, listTest)
return listTest

Because your redefining result2 everytime. Keep result2 outside the function and it should work.
Also you could consider doing data*times to replicate if data is a list or simply do
(result2.append(data))*times

In the recursion, each time replicate_recur is called, a fresh result2 in new name space is created.
[data] * times
Would do what you are trying to achieve.

Python uses 'Pass-by-Object-reference', which is why either of the below code should do the trick in your case.
def replicate_recur(times, data, result2 = []):
if times == 1:
result2.append(data)
else:
result2.append(data)
replicate_recur(times - 1, data)
return result2
When called:
>>> replicate_recur(4, 2)
[2, 2, 2, 2]
Alternatively, you could create the result2 list and pass it as an argument to the function. The argument is 'Passed by Object reference', so the same result object is being modified inside the function as well.
def replicate_recur(times, data):
if times == 1:
result2.append(data)
else:
result2.append(data)
replicate_recur(times - 1, data)
return result2
When called:
>>> result2 = []
>>> replicate_recur(4, 2)
[2, 2, 2, 2]
Refer to the below link to learn more about Pass by Object Reference.
Python:Pass By Object Reference

Related

Python Review: Why doesn't code 1 produce same result as code 2?

Why does code 1 output 28 (not what I want) but code 2 outputs [7, 14, 21, 28] (what I want)?
#Code 1
def dog_years(age):
return age * 7
def my_pets_age(func, param_list):
for i in param_list:
func(i)
return func(i)
dog_age = my_pets_age(dog_years, [1, 2, 3, 4])
print(dog_age)
Is there a way for me to write this so that I don't need to create a result variable with an empty array?
#Code 2
def dog_years(age):
return age * 7
def my_pets_age(func, param_list):
result = []
for i in param_list:
result.append(func(i))
return result
dog_age = my_pets_age(dog_years, [1, 2, 3, 4])
print(dog_age)
In code 1, you're not storing the value returned by func(i) anywhere on each iteration. The value is computed and then just thrown away. Then, once the loop is done, the value of i is 4 because that's the last value in the param_list so you return func(4) which is 28.
In the second code, you're actually storing the intermediate values by appending them to the result array.
You can rewrite the second code as:
def my_pets_age(func, param_list):
return [func(i) for i in param_list]
Look at your code #1. Where do you use the result of the func calls from the loop? (Hint: You don't)
There are only four ways information leaves a function:
Through the return value
(For generators) Through a yield expression
Via an exception being raised
By changes to external state (storing to globals, attributes of outside objects or self, etc.)
The only one of those that applies in either example is #1. In the first block of code, you ignore everything you do in the loop aside from the assignment to i, so all it does is return func(i) where i is the last value looped over. In the second block of code, you build a list of all the results and return that, so you get all of the results, not just the last one.

A function that creates a lists with input from another function

I have a function that will run a couple of times (in a recursive function, so with a 'while' condition). Everytime it runs, it will return a certain integer. So for example, the first time it runs it returns a 3, the second time a 5 and the third time a 9.
Now I need to save these returns in a list. So I thought to create a separate function that would take these values and store them. So the endstate I'm looking for is to have a list = [3,5,8].
B = [3,6,5,7,8,10]
def function_1(A):
for i in range(len(A)/2):
factor = A[2*i]
list_of_diagonals(factor)
return factor`
def list_of_diagonals(d):
factor_list = []
factor_list = factor_list.append(d)
return factor_list`
Now I would expect that print function_1(B) would produces [3,5,8] but instead it just produces 8.
I think it has something to do with the fact that I define factor_list=[] right at the start of the function, but how could I work around that?
using generator you can do this this way , better , readable and more pythonic
B = [3,6,5,7,8,10]
def function_1(A):
for i in range(len(A)//2):
factor = A[2*i]
yield factor
result = list(function_1(B))
# output [3, 5, 8]
you are creating empty factor_list every time whenever list of diagonals call happens. Actually you don't need another function to store result in list , try below code:
B = [3,6,5,7,8,10]
def function_1(A):
l1 = []
for i in range(len(A)/2):
factor = A[2*i]
l1.append(factor)
return l1
print function_1(B)
Other users already pointed the option to use a list directly in the first method, but I'd suggest one way to refactor your code to make it work.
def function_1(array):
list_of_diagonals_ = [] # <-- initialize the recipient
for i in range(len(array)//2): # <-- # // to return integer
factor = array[2*i]
list_of_diagonals_ = list_of_diagonals(factor, list_of_diagonals_) # <-- call the function and store to recipient
return list_of_diagonals_ # <-- return the recipient
def list_of_diagonals(element, factor_list = None): # <-- need an argument to memorize past results
if factor_list == None: factor_list = [] # <-- just in case
factor_list.append(element)
return factor_list
B = [3,6,5,7,8,10]
print (function_1(B))
#=> [3, 5, 8]
The following codes is under Python2.7
using islice in itertools can handle your case
from itertools import islice
B = [3, 6, 5, 7, 8, 10]
def function_1(A):
return islice(A, 0, None, 2)
# [3, 5, 8]
print(list(function_1(B)))

What is the best way to fix a list index out of range exception?

I have written this recursive code in Python:
def suma(i,l):
if i == 0:
return l[i]
else:
return suma(i-1,l)+l[i]
And whenever I call the function by suma(3,[7,2,3]) and run it, I get this error message:
List index out of range on line return suma(i-1,l)+l[i]
Ok, I'm going to assume that the intent here is to recursively add the first i elements of l and return the result. If so, here's a concise way to do so:
def suma(i,l):
return 0 if i == 0 else suma(i-1,l)+l[i-1]
This is equivalent to:
def suma(i,l):
if i == 0:
return 0
else
return suma(i-1,l)+l[i-1]
It's unorthodox, but you could just call your suma() function with the first argument reduced by 1:
>>> l = [7, 2, 3]
>>> suma(len(l)-1, l)
12
But it could be better written like this:
def suma(l):
if len(l) > 1:
return suma(l[:-1]) + l[-1]
return l[0]
>>> suma([7,2,3])
12
>>> suma(range(1,11))
55
This has the advantage of not requiring the length of the list to be passed to the sum function at all - the length is always available using len().

Why won't my Python function be recursive/call itself?

I am making a String Rewriting Function that takes a string and rewrites it according to the rules in a dictionary. The code works perfectly fine once but I need it to call itself n times and print the 'nth' rewritten string. The code that works that I need to be recursive is:
S = "AB"
def srs_print(S, n, rules):
'''
A function that takes a dictionary as SRS rules and prints
the output
'''
axiom = list(S)
key = []
value = []
output = ''
for k in rules:
#Inputs the keys of the rules dictionary into a new list
key.append(k)
#Inputs the value of the rules dictionary into a new list
value.append(rules[k])
for x in axiom:
if x in key:
axiomindex = key.index(x)
output += value[axiomindex]
else:
output += x
S = output
return S
#j = srs_print(S, 5, {'A':'AB', 'B': 'A'})
#print(j)
#while len(range(n)) > 0:
# S = srs_print(S, n, rules)
# n = n-1
#print("The", n, "th rewrite is " )
#j = srs_print(S, 5, {'A':'AB', 'B': 'A'})
print(srs_print("A", 5, {'A':'AB', 'B': 'A'}))
This turns "A" into "AB" but I need it to put 'S' back into the function and run again 'n'times. As you can see, some of the commented code are lines I have tried to use but have failed.
I hope I've explained myself well enough.
If I understand correctly, you pass "n" to the function as a way to count how many times you need to call it.
You could probably get away with enclosing the whole body of the function in a for or a whileloop.
If you want it to be recursive anyway, here's how it could work:
You need to have "two" return statements for your function. One that returns the result (in your case, "S"), and another one, that returns srs_print(S, n-1, rules)
Ex:
if n > 0:
return srs_print(S, n-1, rules)
else:
return S
I suggest you take some time and read this, to get a better understanding of what you want to do and whether or not it is what you should do.
You definitly don't need recursion here. First let's rewrite your function in a more pythonic way:
def srs_transform(string, rules):
'''
A function that takes a dictionary as SRS rules and prints
the output
'''
# the short way:
# return "".join(rules.get(letter, letter) for letter in string)
# the long way
output = []
for letter in string:
transformed = rules.get(letter, letter)
output.append(transformed)
return "".join(output)
Now we add a wrapper function that will take care of applying srs_transform a given number of times to it's arguments:
def srs_multi_transform(string, rules, times):
output = string
for x in range(times):
output = srs_transform(output, rules)
return output
And now we just have to call it:
print(srs_transform("A", {'A':'AB', 'B': 'A'}, 5))
>> ABAABABAABAAB
Why not simply use a for-loop?
def srs_print(S, n, rules):
for _ in range(n):
S = ''.join(rules.get(x, x) for x in S)
return S

list checking in python

Hello there
i've written a small functions that takes two lists and compares them for duplicating pairs,
and returns a boolean value.
For instance ([1,2,3],[2,1,4]) returns false and ([1,2,3],[3,4,5]) returns true
But i would like the argument to take any given amount of lists, instead of just two.
Here's my program so far:
def check(xrr, yrr):
x = xrr[:]
x.sort()
y = yrr[:]
y.sort()
for i in range(len(x)-1):
if x[i]==y[i]:
return False
return True
But also it isnt exactly working correctly yet, as ([1,2,3],[1,4,5]) also returns false.
Any hints and ideas is highly appreciated
import itertools
def check(*args):
r = None
for l in args:
s = set(frozenset(x) for x in itertools.combinations(l, 2))
if r is None:
r = s
else:
r &= s
if not r:
return True
return False
print check([1, 2, 3], [3, 4, 5])
print check([1, 2, 3], [2, 1, 4])
def dupLists(List0,*Lists):
result=set(List0)
for l in Lists:
result=result.intersection(l)
if len(result)<2:
return True
return False
As a naive implementation, you can define a list of lists and hash the internal representation. For instance:
def check(given):
hash = {}
for li in given:
for val in li:
if val in hash:
return False
hash[val] = 1
return True
This works if your input data sets contain a small number of unique elements relative to memory. If you expect to receive extremely large data sets, you might need to consider a more elaborate approach.
Also notable is this will return False for repeating elements within the same data set, and for repeating values at any location within the data set. This is trivial to refactor, or to rewrite entirely as the other solutions listed here.

Categories