Return a list recursively - python

I need help with recursion I have a code right here which turns an integer into a list of strings. However, I'm struggling to make it recursive. Here is what I have so far.
def turnList( a ):
b = str(a)
c = []
for digit in b:
c.append(digit)
return c

For a recursive function you need a base case, i.e. when we have finished and no longer need to recurse and a generic recursive case
def turnList(a):
a=str(a)
if len(a)==1:
return [a]
else:
return [a[0]] + turnList(a[1:])
Our base case is when our recursive function gets a string of length one. And our recursive case returns the first value in its input as a string (in a list) combined with the list of all the 'future' recursive strings.

Start with a base case, in this case empty list for zero, then define the recursive behavior.
def turnList(a):
if a == 0: # base case
return []
a,d = divmod(a,10) # strip off last digit
return turnList(a) + [str(d)] # recurse
print(turnList(123))
Output:
['1', '2', '3']

There are multiple ways to do recursion. Here, we adjust bIndex.
b = "hello"
def turnList(c, bIndex):
if len(b) == bIndex:
return c
return turnList(c + [b[bIndex]],bIndex+1)
print(turnList([],0))

global an
an = []
def turnList(a):
global an
b=str(a)
an.append(b[len(b)-1])
try:
return turnList(int(b[:len(b)-1]))
except ValueError as e:
an.reverse()
return an
m = turnList(10)
print(m)
this might be the best i've ever written

Related

is there an easier way to write this code pattern?

I am building an evaluator and often encounters this code pattern. Is there a simpler (shorter, more Pythonic, etc) way to write this? It should either return None if the list of operands is empty, the first operand if there is only one to process, and actually create an Add node by calling a function otherwise.
# l contains a list of operands to process
if not l: ans = None
elif len(l) == 1: ans = l[0]
else: ans = createAddNode(*l) # returns Add(a, b, c, ...)
return ans
I find myself repeating this code pattern for various operations like subtract, multiply, divide, etc
Since in python you do not have to specify the return type of a function, you can omit the first line.
if l:
ans = l[0] if len(l) == 1 else createAddNode(*l)
return ans
It's quite hard to answer this without context but I will try and give some suggestions
def test(l):
# l contains a list of operands to process
if not l:
ans = None
elif len(l) == 1:
ans = l[0]
else:
ans = createAddNode(*l) # returns Add(a, b, c, ...)
return ans
at the very least you should have these if statements on separate lines for readability.
if not l:
ans = None
This statement is rather redundant as you are already evaluating whatever is stored in the collection "l" to empty
elif len(l) == 1:
ans = l[0]
this suggestion depends on what "createAddNode" does but once again this seems rather redundant. I would find a way to evaluate this expression inside "createAddNode".
def test(l):
# l contains a list of operands to process
if l:
return createAddNode(*l) # returns Add(a, b, c, ...)
this would be my final function assuming you refactor createAddNode to handle the base case where length is one. This will return None if l is empty
Just as a side note I don't see a point in unpacking a variable amount of arguments in your "createAddNode" function. Odds are you can probably just do this with a for loop, but this obviously depends on what you are trying to unpack.

Why isn't my return command being obeyed?

I'm trying to write a function to return the longest common prefix from a series of strings. Using a debugger, saw that my function reaches the longest common prefix correctly, but then when it reaches the statement to return, it begins reverting to earlier stages of the algorithm.
For test case strs = ["flower","flow","flight"]
The output variable holds the following values:-
f > fl > f
instead of returning fl.
Any help would be appreciated, because I don't really know how to Google for this one. Thank you.
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
#if they are the same
#add one char to output
#run again on sliced list
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
This can be handled with os.path.commonprefix.
>>> import os
>>> strs = ["flower","flow","flight"]
>>> os.path.commonprefix(strs)
'fl'
It doesn't "revert". longestCommonPrefix potentially calls itself - what you're seeing is simply the call-stack unwinding, and flow of execution is returning to the calling code (the line that invoked the call to longestCommonPrefix from which you are returning).
That being said, there's really no need to implement a recursive solution in the first place. I would suggest something like:
def get_common_prefix(strings):
def get_next_prefix_char():
for chars in zip(*strings):
if len(set(chars)) != 1:
break
yield chars[0]
return "".join(get_next_prefix_char())
print(get_common_prefix(["hello", "hey"]))
You are looking at the behavior...the final result...of recursive calls to your method. However, the recursive calls don't do anything to affect the result of the initial execution of the method. If we look at the few lines that matter at the end of your method:
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
The problem here is that since output is immutable, its value won't be changed by calling longestCommonPrefix recursively. So from the standpoint of the outermost call to longestCommonPrefix, the result it will return is determined only by if same(s) is true or false. If it is true it will return s[0], otherwise it will return ''.
The easiest way to fix this behavior and have your recursive call affect the result of the prior call to the method would be to have its return value become the value of output, like this:
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output
This is a common code pattern when using recursion. Just this change does seem to give you the result you expect! I haven't analyzed your whole algorithm, so I don't know if it becomes "correct" with just this change.
Can you try this? I
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
# Can you Try this revision?
# I think the problem is that your new version of output is being lost when the fourth called function returns to the third and the third returns to the second, etc...
# You need to calculate a new output value before you call recursively, that is true, but you also need a way to 'store' that output when that recursively called function 'returns'. Right now it disappears, I believe.
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output

Trying to learn how loops work, what is going wrong?

The question is :
Given a string, return a string where for every char in the original, there are two chars.
This is my attempt:
def double_char(str):
n = 0
for x in range(0, len(str)):
return 2*str[n]
n = n+1
When I run it, it only returns 2 versions of the first letter and doesn't loop properly. So for double_char(Hello) it just returns HH.
What is going wrong? Thanks in advance for any help, sorry for the really beginner question.
The return is causing your function to return in the first iteration so it just returns 2 of the first letter.
What you may have intended to write was something like
def double_char(s):
n = 0
r = ''
for x in range(0, len(s)):
r += 2*s[n]
n = n+1
return r
Building a string incrementally that is just 2 of each character.
A neater refactor of that function (without duplicating the other answer by using a comprehension) is
def double_char(s):
r = ''
for c in s:
r += 2*c
return r
You also should not use str as a variable name. It is a built in type and you are hiding that by defining a variable called str.
return returns control to the caller once reached, thus exiting your for loop prematurely.
Here's a simpler way to do that with str.join:
def double_char(s):
return ''.join(i*2 for i in s)
>>> s = 'Hello'
>>> double_char(s)
'HHeelllloo'
Do not use str as name to avoid shadowing the builtin str function.
Here is a different way to solving the question.
def double_char(str):
new_str = ""
for i in range(len(str)):
new_str += (str[i]*2)
return new_str
double_char('Hello')
'HHeelllloo'
def double_char(str):
string = ''
for i in range(len(str)):
string += str[i] * 2
i += 1
return string

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

Writing filter() function but getting typeError

my code consists of me recreating the function 'filter()' and using it with a function to filter words longer than 5 characters. It worked with the actual function filter when I tried it btw...I'm using python 3+
def filter1(fn, a):
i = 0
while i != len(a):
u = i - 1
a[i] = fn(a[i], a[u])
i += 1
return a
def filter_long_words(l):
if len[l] > 5:
return [l]
listered = ['blue', 'hdfdhsf', 'dsfjbdsf', 'jole']
print(list(filter1(filter_long_words, listered)))
getting error
TypeError: filter_long_words() takes 1 positional argument but 2 were given
You are passing two parameters to fn (which refers to filter_long_words) here:
a[i] = fn(a[i], a[u])
But filter_long_words only accepts one parameter.
Notes:
You can loop through lists using for item in my_list, or if you want index as well for index, item in enumerate(my_list).
I think you might get an IndexError since u will be -1 in the first round of your loop.
The filter function can also be expressed as a list comprehension: (item for item in listered if filter_long_words(item))
My version of filter would look like this, if I have to use a for loop:
def my_filter(fn, sequence):
if fn is None:
fn = lambda x: x
for item in sequence:
if fn(item):
yield item
Since you have stated that you are using Python 3, this returns a generator instead of a list. If you want it to return a list:
def my_filter(fn, sequence):
if fn is None:
fn = lambda x: x
acc = []
for item in sequence:
if fn(item):
acc.append(item)
return acc
If you don't need to use a for loop:
def my_filter(fn, sequence):
if fn is None:
fn = lambda x: x
return (item for item in sequence if fn(item))
Your're calling fn with 2 parameters in filter1(fn, a), and since you've passed filter_long_words() to filter1 as fn, that triggers the error.
But there's more weird stuff:
I don't understand the magick of filter1 or what you were trying to
accomplish, but it seems to me that you don't have a clear idea what to do.
But if you want to mimic (somehow) how filter works, you have to return a
list which contains only items for which the fn function returns true. When
you know this, you can rewrite it - here are a few suggestions for rewrite
# explicit, inefficient and long, but straightforward version:
def filter1(fn, a):
new_list = []
for item in a:
if fn(item):
new_list.append(item):
return new_list
# shorter version using list comprehensions:
def filter1(fn, a):
return [item for item in a if fn(item)]
The filter_long_words function is wrong too - it should return True or
False. The only reason why it could work is because any non-empty list is
treated as True by python and default return value of a function is None,
which translates to False. But it's confusing and syntactically wrong to use
len[l] - the proper usage is len(l).
There are a few suggestions for rewrite, which all returns explicit boolean
values:
# unnecessary long, but self-explanatory:
def filter_long_words(l):
if len(l) > 5:
return True
else
return False
# short variant
def filter_long_words(l):
return len(l) > 5
You are calling "filter_long_words" with 2 parameter => fn(a[i], a[u]) also there is an error
def filter_long_words(l):
if **len[l]** > 5:
return [l]
len is builtin method it should be len(l)

Categories