Add numbers in a list using recursion in Python - python

The given template is:
def total(lst):
return (
#### YOUR CODE HERE ####
#### DO NOT WRITE CODE OUTSIDE OF THIS ####
#### RETURN STATEMENT ####
)
def getValue():
try:
return int(input())
except:
return None
v = getValue()
myLst = [v]
while v != None:
v = getValue()
if v != None:
myLst.append(v)
print(total(myLst))
I have gotten this:
def total(lst):
return (
if lst ==1:
lst[0]
else:
lst[0]+total(lst[0:])
)
def getValue():
try:
return int(input())
except:
return None
v = getValue()
myLst = [v]
while v != None:
v = getValue()
if v != None:
myLst.append(v)
print(total(myLst))
The input is:
1
2
3
4
5
It should print the sum of all the numbers.
But this gives me an error:
File "main.py", line 3
if lst ==1:
^
SyntaxError: invalid syntax
Please help me figure out what I did wrong! Thanks!

You put an if statement inside a return expression. Putting a statement inside an expression is a syntax error. Use an if expression instead, such as
return (
lst[0] if lst == 1 else lst[0] + total(lst[0:])
)

Since you're only allowed to write code inside an expression, you need to use a slightly different syntax for if-statements.
if len(lst) == 1:
lst[0]
else:
lst[0]+total(lst[0:])
can be written as a single statement as:
lst[0] if len(lst) == 1 else lst[0]+total(lst[0:])
(assuming you wanted to check the length of the list, rather than doing a compare against an int, which is always going to be false)

Related

Python Function Recursive - Give Index of first occurence of 'number' in 'list' AND return None if number not in list

I have an exercice where I need to find the index of the first occurence of a number in list. But I also need to return None if index can't be found, meaning the number is not in list.
I need to do that with a recursive function in Python.
I already created a code that does: "find the index of the first occurence of a number in list". And it works.
def index(lst, number_find):
if lst == []:
return None
elif lst[0] == number_find:
return 0
else:
return 1 + index(lst[1:], number_find)
liste = range(51)
print(index(liste, 42))
But I can't write the code that manages the case if the number is not in list.
I have done that:
def index(lst, number_find):
if number_find not in lst:
return None
elif lst == []:
return None
elif lst[0] == number_find:
return 0
else:
return 1 + index(lst[1:], number_find)
liste = range(51)
print(index(liste, 42))
But the use of "not in" is not good here for me because that seems to use some iterative code that I can't use.
You have to protect against the case where None comes back from the recursive call, because 1 + None will raise a TypeError:
def index(lst, number_find):
if lst == []:
return None
elif lst[0] == number_find:
return 0
else:
i = index(lst[1:], number_find)
if i is not None:
return 1 + i
return None # not strictly necessary as None returned implicity
Of course, when you return from every if-block, you can omit any else. Also, None is the default return value, so you can shorten your logic
def index(lst, number_find):
if lst:
if lst[0] == number_find:
return 0
if (i := index(lst[1:], number_find)) is not None:
return 1 + i
Btw, since slicing is O(N) here, all these approaches are quadratic. So here is a solution that has linear complexity:
def index(lst, number_find):
def rec(it, i=0):
if (n := next(it, None)) is not None:
return i if n == number_find else rec(it, i+1)
return rec(iter(lst))
The accepted answer by user2390182 explains in detail how to handle the possible None value returned by the recursive call.
A different approach is to write the function in a tail-recursive way:
def index(lst, number_find, acc=0):
if lst == []:
return None
elif lst[0] == number_find:
return acc
else:
return index(lst[1:], number_find, acc+1)
Note that python doesn't perform tail-rec optimization; but this approach still avoids the 1+None issue.

How do I split this into a separate if statement?

I'm trying to split the following code into a separate if statement.
def second_half(s):
return s[len(s)//2 if len(s)%2 == 0 else ((len(s)//2)+1):]
I've already tried doing the following:
def second_half(s):
if len(s) % 2 == 0:
return s[len(s)//2]
else:
return s[((len(s)//2)+1):]
and receive the following output in my doctest (although majority of my other tests passed):
Failed example:
second_half("abcdef")
Expected:
'def'
Got:
'd'
Would appreciate any help. Cheers.
In your original list-comprehension code, the start index of the slice is calculated and the last index is taken as (len(s)
But when you translate this into two if-statements, You forgot the slice operator : in the the first if condition, which caused only one element to be returned, but what you want is the whole slice in both if conditions, which will happen when you do return s[len(s)//2:] instead of return s[len(s)//2] in the first if condition
So the updated code will be
def second_half(s):
if len(s) % 2 == 0:
#Added the missing slice
return s[len(s)//2:]
else:
return s[((len(s)//2)+1):]
And the code will work as expected
print(second_half('abcde'))
#de
print(second_half('abcdef'))
#def
As commented, your first return is missing the colon.
This is called list slicing, see here for more info.
def second_half_original(s):
return s[len(s)//2 if len(s)%2 == 0 else ((len(s)//2)+1):]
def second_half_split(s):
if len(s) % 2 == 0:
return s[len(s) // 2:]
else:
return s[len(s)//2 + 1:]
Result:
>>> def second_half_original(s):
... return s[len(s)//2 if len(s)%2 == 0 else ((len(s)//2)+1):]
...
>>> def second_half_split(s):
... if len(s) % 2 == 0:
... return s[len(s) // 2:]
... else:
... return s[len(s)//2 + 1:]
...
>>> s = 'abcdef'
>>> print('Old\t{old}\nNew\t{new}'.format(
... old=second_half_original(s),
... new=second_half_split(s)
... )
... )
Old def
New def
whats happening here:
len(s)//2 if len(s)%2 == 0 else ((len(s)//2)+1)
Ternary operator expression:
syntax:
value_when_true if condition else value_when_false
this part of code will return integer (some_integer)
and then you will have:
s[some_integer:] # a[start:] items start through the rest of the array
Slicing strings:
Syntax:
substring = original_string[first_pos:last_pos]
def second_half(s):
if len(s) % 2 == 0:
n=len(s) // 2
else:
n=(len(s)//2)+1
return s[n:]
print (second_half("abcdef"))
def second_half(s):
if len(s) % 2 == 0:
return s[len(s)//2:]
else:
return s[len(s)//2)+1]
output:
def

why does this get an error and this doesn't?

i'm working through a hackerrank problem: https://www.hackerrank.com/challenges/kaprekar-numbers/problem
and kept having to deal with this error:
ValueError: invalid literal for int() with base 10: ''
the line 12 of code in mine that churned out error, is in the working code too. So i don't understand why mine didn't work :( please help
this is my code:
a = input()
b = input()
l = []
for i in range(a, b + 1):
s = i*i
s = str(s)
if i == 1:
l.append(i)
length = len(s)
if length <= 1:
pass
temp = int(s[0:length/2]) + int(s[length/2:]) #error came from this line
if temp == i:
l.append(i)
else:
pass
if not l:
print "INVALID RANGE"
else:
print " ".join(map(str, l))
and this is the one that works:
def kaprekar(i):
if i == 1:
return True
s = i ** 2
s = str(s)
length = len(s)
if len(s) <= 1:
return False
temp = int(s[0:length/2]) + int(s[length/2:])
if temp == i:
return True
else:
return False
a = input()
b = input()
l = []
for i in range(a, b + 1):
if kaprekar(i):
l.append(i)
if not l:
print "INVALID RANGE"
else:
print " ".join(map(str, l))
if length <= 1:
pass
pass literally doesn't do anything, so this check doesn't do anything. Whether the length is or isn't <= 1, you're proceeding to int(s[length/2:]), which will produce said error in case the string is too short.
However, return False exits the function and the following code will not execute, so that check protects you from trying to process short strings.

Evaluating Infix Expressions Using Stacks in Python: I cant find my error

after looking at this code for 2 days i decided to get some help. this is my fist time asking a question so please bear with me.
my coding experience is minimal and my knowledge goes about as far as the code shown, try to keep things simple.
for a class i'm taking i have to write code to correctly perform order of operations this is my finished code:
import operator
class stack:
def __init__(self):
self._stack = []
def __len__(self):
return len(self._stack)
def is_empty(self):
return len(self._stack) == 0
def push(self, e):
self._stack.append(e)
def top(self):
if self.is_empty():
print ('stack is empty')
return self._stack[-1]
def pop(self):
if self.is_empty():
print ('stack is empty')
return
return self._stack.pop()
def apply(a,b,c):
ops2 = {"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv }
op_char = c
op_func = ops2[op_char]
result = op_func(float(a), float(b))
return result
user = '6 - 5 ( 5 - 3 ) * (4 + 2 )'
#user = input("Enter an expression: ")
print(user)
exp = user.split()
nums = '1234567890'
ops = ['*', '/', '+', '-']
par = ['(', ')']
num = stack()
op = stack()
for each in exp:
print(each)
if each in nums:
num.push(each)
if each == par[0]:
op.push(each)
if each in ops:
if each == ops[2] or ops[3]:
op.push(each)
if each == ops[0] or ops[1]:
while op.top() == (ops[2] or ops[3]) and len(op) > 0 and len(num) >= 2:
ans = apply(num.pop(),num.pop(),op.pop())
num.push(ans)
op.push(each)
if each == par[1]:
while op.top() != "(":
ans = apply(num.pop(),num.pop(),op.pop()) # this line is poping the empty stack
num.push(ans)
op.pop()
while op.is_empty() != True:
ans = apply(num.pop(),num.pop(),op.pop())
num.push(ans)
print(ans)
or so i thought...
when i run this i get a stack is empty error from the if each == par[1] loop and i can not figure out why. the expression i used is suppose to equal -6.0 any help is appreciated.
edit: after changing the code i am in a similar situation and assume that i made a error in pushing or poping somewhere. After walking through the code again i still cant find the error. Again, any help is appreciated.
I'm afraid other issues exist with this code (which you will discover once you fix the following), but the problem you refer to in your question comes from your pop method:
def pop(self):
if self.is_empty():
print ('stack is empty') # still proceeds to the next line
return self._stack.pop() # won't work if self._stack is empty
This raises an IndexError because you cannot pop from an empty list, and your return statement will be run whether the list is empty or not. Perhaps you are after something like the following (?):
def pop(self):
if self.is_empty():
print ('stack is empty')
return # now you need to deal with the returned None value
return self._stack.pop() # only if not empty

Inteviewstreet Median in python. Fails on all but the first test case

So i wrote this code and it passes the first test case, and fails all the rest. However, I can't seem to find an input that breaks it. Maybe it's because I've been staring at the code too long, but i would appreciate any help.
The algorithm uses two priority queues for the smallest and largest halves of the current list. Here's the code:
#!/bin/python
import heapq
def fix(minset, maxset):
if len(maxset) > len(minset):
item = heapq.heappop(maxset)
heapq.heappush(minset, -item)
elif len(minset) > (len(maxset) + 1):
item = heapq.heappop(minset)
heapq.heappush(maxset, -item)
N = int(raw_input())
s = []
x = []
for i in range(0, N):
tmp = raw_input()
a, b = [xx for xx in tmp.split(' ')]
s.append(a)
x.append(int(b))
minset = []
maxset = []
for i in range(0, N):
wrong = False
if s[i] == "a":
if len(minset) == 0:
heapq.heappush(minset,-x[i])
else:
if x[i] > minset[0]:
heapq.heappush(maxset, x[i])
else:
heapq.heappush(minset, -x[i])
fix(minset, maxset)
elif s[i] == "r":
if -x[i] in minset:
minset.remove(-x[i])
heapq.heapify(minset)
elif x[i] in maxset:
maxset.remove(x[i])
heapq.heapify(maxset)
else:
wrong = True
fix(minset, maxset)
if len(minset) == 0 and len(maxset) == 0:
wrong = True
if wrong == False:
#Calculate median
if len(minset) > len(maxset):
item = - minset[0]
print int(item)
else:
item = ((-float(minset[0])) + float(maxset[0])) / 2
if item.is_integer():
print int(item)
continue
out = str(item)
out.rstrip('0')
print out
else:
print "Wrong!"
Your original was not so legible, so first I made it object-oriented:
MedianHeapq supports methods rebalance(), add(), remove(), size(), median(). We seriously want to hide the members minset,maxset from the client code, for all sorts of sensible reasons: prevent client from swapping them, modifying them etc. If client needs to see them you just write an accessor.
We also added a __str__() method which we will use to debug visually and make your life easier.
Also added legibility changes to avoid the indexing with [i] everywhere, rename s,x arrays to op,val, add prompts on the raw_input(), reject invalid ops at the input stage.
Your actual computation of the median confuses me (when do you want float and when integer? the rstrip('0') is a bit wack), so I rewrote it, change that if you want something else.
A discussion of the algorithm is here.
Now it is legible and self-contained. Also makes it testable.
You might be making sign errors in your code, I don't know, I'll look at that later.
Next we will want to automate it by writing some PyUnit testcases. doctest is also a possibility. TBC.
Ok I think I see a bug in the sloppiness about locating the median. Remember the minset and maxset can have a size mismatch of +/-1. So take more care about precisely where the median is located.
#!/bin/python
import heapq
class MedianHeapq(object):
def __init__(self):
self.minset = []
self.maxset = []
def rebalance(self):
size_imbalance = len(self.maxset) - len(self.minset)
if len(self.maxset) > len(self.minset):
#if size_imbalance > 0:
item = heapq.heappop(self.maxset)
heapq.heappush(self.minset, -item)
#elif size_imbalance < -1:
elif len(self.minset) > (len(self.maxset) + 1):
item = heapq.heappop(self.minset)
heapq.heappush(self.maxset, -item)
def add(self, value, verbose=False):
if len(self.minset) == 0:
heapq.heappush(self.minset,-value)
else:
if value > self.minset[0]:
heapq.heappush(self.maxset, value)
else:
heapq.heappush(self.minset, -value)
self.rebalance()
if verbose: print self.__str__()
return False
def remove(self,value,verbose=False):
wrong = False
if -value in self.minset:
minset.remove(-value)
heapq.heapify(self.minset)
elif value in maxset:
maxset.remove(value)
heapq.heapify(self.maxset)
else:
wrong = True
self.rebalance()
if verbose: print self.__str__()
return wrong
def size(self):
return len(self.minset)+len(self.maxset)
def median(self):
if len(self.minset) > len(self.maxset):
item = - self.minset[0]
return int(item)
else:
item = (-self.minset[0] + self.maxset[0]) / 2.0
# Can't understand the intent of your code here: int, string or float?
if item.is_integer():
return int(item)
# continue # intent???
else:
return item
# The intent of this vv seems to be round floats and return '%.1f' % item ??
#out = str(item)
#out.rstrip('0') # why can't you just int()? or // operator?
#return out
def __str__(self):
return 'Median: %s Minset:%s Maxset:%s' % (self.median(), self.minset,self.maxset)
# Read size and elements from stdin
N = int(raw_input('Size of heap? '))
op = []
val = []
while(len(val)<N):
tmp = raw_input('a/r value : ')
op_, val_ = tmp.split(' ')
if op_ not in ['a','r']: # reject invalid ops
print 'First argument (operation) must be a:Add or r:Remove! '
continue
op.append(op_)
val.append(int(val_))
mhq = MedianHeapq()
for op_,val_ in zip(op,val): # use zip to avoid indexing with [i] everywhere
wrong = False
if op_ == 'a':
wrong = mhq.add(val_)
elif op_ == 'r':
wrong = mhq.remove(val_)
assert (mhq.size()>0), 'Heap has zero size!'
assert (not wrong), 'Heap structure is wrong!'
if not wrong:
print mhq.__str__()

Categories