Summing objects in recursive python function - python

I need to sum objects (strings, ints, etc.) in one function (don't create other function, it can be done within one). It should work this way: When given my_sum([[['s'],'ta'],['c',['k']]]), it should return 'stack'.
I came up with this:
def my_sum(array):
if not array: #empty array
return None
else:
for item in array:
if type(item) == list:
my_sum(item)
else:
print(item)
It of course is not doing what it should be, I was just playing around with it trying to come up with something. This code above returns this:
s
ta
c
k
I think I am not that far from result as I have what I need, but here is the problem how can I sum up those items ? I can't write result = '' anywhere in the function and then return it, because it would be deleting every time there would be recursion call. Also I don't want global variables (if anyone would think of that). Maybe I am just being stupid and can't see that it is one simple thing, pardon me if it is so.
Thank you for every answer!

The common accumulating pattern is:
result = <init value>
for item in argument:
result = result <operator> item
return result
(this can be written more concisely, but that's not the point for now).
Applied to your problem:
def my_sum(items):
result = ''
for item in items:
if type(item) == list:
result += my_sum(item)
else:
result += item
return result
Note that type(x) == y is frowned upon in Python, isinstance is considered better style.
Homework: extend the function so that it works for these arguments too:
print my_sum([[['s'],'ta'],('c',('k')), {('over'), ('flow')}])

Related

What's the different between calling function with and without 'return' in recursion?

I tried to create recursive function for generating Pascal's triangle as below.
numRows = 5
ans=[[1],[1,1]]
def pascal(arr,pre,idx):
if idx==numRows:
return ans
if len(arr)!=idx:
for i in range (0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
if len(arr)==idx:
arr+=[1]
ans.append(arr)
pascal([1],arr,idx+1)
a = pascal([1],ans[1],2)
return a
The output I got was an empty list [ ]. But if I add return when calling pascal as
return pascal([1],arr,idx+1)
the output was correct [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]].
As I understand, a should have been assigned by return ans. Then why a failed to get an answer when calling pascal without return and why return is necessary in this case?
When you have recursion, you usually combine the returns in some way. Could be a sum, like fibonacci:
fibonacci(n+1) = fibonnaci(n)+fibonacci(n-1)
Or appending a line to a matrix, like your case. Anyway, if you don't have a return, you have no information to combine! Consider the fibonnaci case without return:
def fibonnaci(n):
if n<2:
return 1
fib_ans = fibonnaci(n-2)+fibonnaci(n-1)
In this case, if I called fibonnaci(0) or fibonnaci(1) the output would be 1, like you return ans if idx == numRows, but if I called fibonnaci(2), then the variable fib_ans would receive 2, which is the expected answer, but it would be available outside the scope of the funtion. Python "would add" return None to the end of my function, just below the fib_ans attribution. So, I need to return fib_ans
Well as far as i know, if you want to get a value back you need the "return" statement...
The point is if you don't have "return", you will be getting no values back...
Hopefully this helps..
For all algol languages that has a return keyword it exits the nearest function completely and the result of it is the result of the expression of the return argument. eg.
def test(v):
if v == 0:
return someFun(10)
...
If v is zero the result of the function is the value returned by someFun(10). The rest of the function denoted by ... is never executed unless v is nonzero.
If we write the same without return:
def test(v):
if v == 0:
someFun(10)
...
Now, when v is zero someFun(10) is still called, but the value returned by it is discarded and in order for it to have any true meaning someFun needs to do some side effects, like printing, storing values, updating object. In addition all the rest of the function denoted by ... is then continued once someFun(10) is done.
For Python and many other languages not having a return at all doesn't mean it doesn't return anything. In Python there is an invisible return None in the last line of every function/method.
When you do pascal([1],arr,idx+1), you are doing the recursive call but then discarding the value which it returns. If you want to return it to the caller, then you need to use explicitly return pascal(...).
In fact recursion is not necessary in this example anyway. You could easily refactor your code to use a simple for loop. For example:
def pascal(numRows):
ans = [[1]]
for _ in range(1, numRows):
pre = ans[-1]
arr = [1]
for i in range(0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
arr+=[1]
ans.append(arr)
return ans
print(pascal(5))
(I'm using the name _ here as the for loop variable according to convention because it is a dummy variable not used inside the loop, but you could use something else e.g. row if you prefer.)
The above is as close to the original code as possible, but you should also consider using arr.append(value) in place of arr += [value] -- this would be the normal way to append a single value to a list.

Changing(replacing) a value in a list without using range(len())

My purpose is to change the value of the elements 3 and 4 to 4 and 3 and I have written a function that takes a list, first number and second number as arguments:
def pre9(the_list, value_to_replace, the_replacing_value):
for i in the_list:
if i == value_to_replace:
value_to_replace = the_replacing_value
elif i == the_replacing_value:
the_replacing_value = value_to_replace
return the_list
I then assign a test-case to a variabel and then print it:
test_pre9 = pre9([1,2,3,4,5,7,3,4], 3, 4)
print(test_pre9)
The result is: [1,2,3,4,5,7,3,4]
I expect it to be: [1,2,4,3,5,7,4,3]
I have for a long time ago written a code that accoplishes this task:
def uppgift_9():
the_list = [3,5,8,9,4,5]
for i in range(len(the_list)-1):
temp = the_list[3]
the_list[3] = the_list[4]
the_list[4] = temp
return the_list
But I've read in many places that using range(len()) is not "pythonic" and it is possible to do anything without using it.
Does anyone know why my code fails?
You don't actually change the item in the list, try this:
def pre9(the_list, value_to_replace, the_replacing_value):
for i, value in enumerate(the_list):
if value == value_to_replace:
the_list[i] = the_replacing_value
elif value == the_replacing_value:
the_list[i] = value_to_replace
return the_list
Now the list will have the actually items changed to what you wanted it to be. Enumerate() returns the index and value of an item in a list, it's very handy! And indeed, the range(len()) is not very pythonic and is usually used when people jump from other languages like Java, C# etc. Using enumerate() is the correct 'pythonic' way of achieving this.

Python syntax to return an expression only if its value is not None

I want to know how to make a function return the return value of a nested function, if the return value of the nested function is not None.
To make my code work, I could just copy the code of the nested function in my main function, but this is too repetitive (DRY). I looked into some questions with copying functions with from functool import partial but this just allows you to have another function with different variables or docstring. Furthermore I've glanced at all related questions and none seem to have an elegant piece of code (to do this simply).
Here the main function ExtractOne is fed a list of numbers. Generally (relevant to my code) the 4th element is one, so that element is checked with CheckIfOne function. If this is the case, the function returns 1 and is thus exited. If that is not the case, then the code continues by checking all the elements in the fed list if they're a one, again, using CheckIfOne for each element. If the element is one, ExtractOne should return 1, thus breaking the for loop and function.
Here's a snippet of what works. It's copying the return value of CheckIfOne (the nested function) onto a variable a, checking if a is not None, and returning a if this is the case.
Example 1:
def CheckIfOne(part):
if part == 1:
return 1
def ExtractOne(parts):
#4th element is generally 1
a = CheckIfOne(parts[3])
if a:
return a
#else scan through the list for 1
for part in parts:
a = CheckIfOne(part)
if a:
return a
>>> ps = [1,2,3,4,5]
>>> ExtractOne(ps)
1
>>>
Here's how I would like it to look like, but of course this is not how nested functions work, the nested function returns a value and this must be copied onto a variable and that variable checked if it's not None and then returned, like in the above snippet.
Example 2:
def CheckIfOne(part):
if part == 1:
return 1
def ExtractOne(parts):
#4th element is generally 1
CheckIfOne(parts[3])
#else scan through the list for 1
for part in parts:
CheckIfOne(part)
>>> ps = [1,2,3,4,5]
>>> ExtractOne(ps)
>>>
However, it does work when I just copy the code of CheckIfOne, but this violates the DRY rule.
Example 3:
def ExtractOne(parts):
#4th element is generally 1
if parts[3] == 1:
return 1
#else scan through the list for 1
for part in parts:
if part == 1:
return 1
>>> ps = [1,2,3,4,5]
>>> ExtractOne(ps)
1
>>>
I expect there to be a simple, pythonic python syntax to just copy the code of the nested function onto the main piece of code like in example 3.
Ignoring for a second that your code won't always have a return value, that the naming convention isn't in itself 'pythonic', and that there are simpler ways to reduce complexity, and assuming that you are just asking the question generically.
There is nothing wrong with calling a separate method, but if you simply want to spare yourself having another top level function and you will only use the code within your function, you can define the function inside the function, like below.
def ExtractOne(parts):
def CheckIfOne(part):
if part == 1:
return 1
#4th element is generally 1
a = CheckIfOne(parts[3])
if a:
return a
#else scan through the list for 1
for part in parts:
a = CheckIfOne(part)
if a:
return a
ps= [1,2,3,4,5]
print(ExtractOne(ps))
You can return multiple numbers, but putting all of your returns into an array (or list) then return them after you have finished.
def foo(numbs):
output = []
...
output.append(data)
...
return output

I have a generator in my Python function; how can I return a modified list?

A little background: I've been trying to code a "Sieve of Eratosthenes" algorithm. At the request of some fine (and very patient) programmers on the StackOverflow Python chatroom, I did some reading on the enumerate() function and found a way to incorporate it into my code (yes, I'm very much a novice here). So far, my (workable; returns expected response) code looks like this:
def SieveErat(n):
numbers = [False]*2+[True]*(n-1)
for index, prime_candidate in enumerate(numbers):
if prime_candidate == True:
yield index
for x in xrange(index*index, n, index):
numbers[x] = False
primes = []
for x in SieveErat(150000):
primes.append(x)
print primes[10002]
Needless to say, the enumerate() function makes coding this much, much less awkward than whatever nested loops I had before. However, I fear that I'm not understanding something about enumerate(), because when I tried to shorten this code by including the appending into the function, I kept getting errors- namely,
File "SievErat.py", line 13
return numbers
SyntaxError: 'return' with argument inside generator
I've also tried appending all the True elements inside the list numbers to a initialized list primes, but found no luck.
Any hints or advice would be very much welcomed.
This has nothing to do with enumerate you are trying to return something in a generator which before python 3.3 is illegal, and from 3.3+ it means something entirely different.
I'd recommend you leave your function a generator if you may use it without needing a list back, and if you want list results then just call list() on the return value:
primes = list(SieveErat(150000)) #this replaces loop with .append
But to understand what went wrong, if your function still has the yield statement in it then it must return a generator object, if you don't want it to return a generator object then remove the yield statement all together:
def SieveErat(n):
numbers = [False]*2+[True]*(n-1)
for index, prime_candidate in enumerate(numbers):
if prime_candidate == True:
#yield index #no yield statement if you want to return the numbers list
for x in xrange(index*index, n, index):
numbers[x] = False
return numbers #return at end
However this would then return a list of True and False instead of the numbers that are True, you can instead hold a separate list with all the prime numbers and .append to it everytime you would yield something:
def SieveErat(n):
numbers = [False]*2+[True]*(n-1)
result = [] #start with no results
for index, prime_candidate in enumerate(numbers):
if prime_candidate == True:
results.append(index) #instead of yield index
for x in xrange(index*index, n, index):
numbers[x] = False
return results
But this feels like a step backwards from a generator, personally I'd just keep what you have posted and cast the result to a list.

Recursive Function in Python adding Odd Values in List

My task is to create a recursive function in Python that takes a list and a value of 0 as its inputs and then adds up all of the odd numbers on the list and returns that value. Below is the code that I have and it keeps returning that the list index is out of range. No matter what I do I can not get it to work.
def addodds2(x,y):
total=0
a=x[y]
while y<len(x):
if a%2!=0:
total+=a
return(addodds2(x,y+1))
else:
return(addodds2(x,y+1))
return(total)
print(addodds2([3,2,4,7,2,4,1,3,2],0))
Since you are trying to solve this recursively, I don't think you want that while loop.
When you are trying to solve a problem recursively, you need two parts: you need a part that does some of the work, and you need a part that handles reaching the end of the work. This is the "basis case".
Often when solving problems like this, if you have a zero-length list you hit the basis case immediately. What should be the result for a zero-length list? I'd say 0.
So, here's the basic outline of a function to add together all the numbers in a list:
Check the length, and if you are already at the end or after the end, return 0. Otherwise, return the current item added to a recursive call (with the index value incremented).
Get that working, and then modify it so it only adds the odd values.
P.S. This seems like homework, so I didn't want to just give you the code. It's easier to remember this stuff if you actually figure it out yourself. Good luck!
Your code should be (the comments explain my corrections):
def addodds2(x,y):
total=0
if y<len(x): #you don't need a while there
a=x[y] #you have to do this operation if y<len(x), otherwise you would get the index error you are getting
if a%2!=0:
total+=a
return total+addodds2(x,y+1) #you have to sum the current total to the result returned by the addodds2() function (otherwise you would got 0 as the final result)
return total
print(addodds2([3,2,4,7,2,4,1,3,2],0))
while y<len(x)
So the last y which is smaller than len(x) is y = len(x) - 1, so it’s the very last item of the list.
addodds2(x,y+1)
Then you try to access the element after that item, which does not exist, so you get the IndexError.
This code can be very short and elegant:
def add_odds(lst, i=0):
try:
return (lst[i] if lst[i] % 2 == 0 else 0) + add_odds(lst, i+1)
except IndexError:
return 0
Note that, in a truly functional style, you wouldn't keep track of an index either. In Python, it would be rather inefficient, though, but recursion isn't recommended in Python anyway.
def add_odds2(lst):
try:
return (lst[-1] if lst[-1] % 2 == 0 else 0) + add_odds2(lst[:-1])
except IndexError:
return 0
To make it work with any kind of sequence, you can do the following:
def add_odds3(it):
it = iter(it)
try:
value = next(it)
return (value if value % 2 == 0 else 0) + add_odds3(it)
except StopIteration:
return 0
It's much more efficient, though there's not much sense in using an iterator recursively...
I realize that little of this is relevant for your (educational) purposes, but I just wanted to show (all of) you some nice Python. :)

Categories

Resources