Calling a function recursively in Python by passing a List - python

I know there are easier ways to create a function which gives you the largest number in a list of numbers but I wanted to use recursion. When I call the function greatest, i get none. For example greatest([1,3,2]) gives me none. If there are only two elements in the list, I get the right answer so I know the problem must be with the function calling itself. Not sure why though.
def compare(a,b):
if a==b:
return a
if a > b:
return a
if a < b:
return b
def greatest(x):
if len(x)==0:
return 0
i=0
new_list=[]
while i< len(x):
if len(x)-i>1:
c=compare(x[i],x[i+1])
else:
c=x[i]
new_list.append(c)
i=i+2
if len(new_list)>1:
greatest(new_list)
else:
return new_list[0]
print greatest([1,3,2])

This line:
if len(new_list)>1:
greatest(new_list) # <- this one here
calls greatest but doesn't do anything with the value it returns. You want
return greatest(new_list)
After fixing that, your function seems to behave (although I didn't look too closely):
>>> import itertools
>>> for i in range(1, 6):
... print i, all(max(g) == greatest(g) for g in itertools.product(range(-5, 5), repeat=i))
...
1 True
2 True
3 True
4 True
5 True

A simple recursion can be like this :
from random import *
def greatest(x,maxx=float("-inf")):
if len(x)>0:
if x[0] > maxx:
maxx=x[0]
return greatest(x[1:],maxx)
else:
return maxx
lis=range(10,50)
shuffle(lis)
print greatest(lis) #prints 49

Related

finding string in a list and return it index or -1

Defining a procedure which return an index of item or -1 if the item not in list
def ser(a,b):
for j in a:
if j == b:
return (a.index(b))
else:
return -1
print (ser([1,2,3],3))
It's always return me -1. If i cut the 'else' part, it works. So why ?
That is because the first time you do not match the condition in your loop you immediately return and leave your method. You need to re-think your logic here to determine what it is you want to do when you don't match. Ultimately, you want to continue looping until you have exhausted your checks.
So, simply set your return -1 outside of your loop. If you go through your entire loop, you have not found your match, so you can then return -1
def ser(a,b):
for j in a:
if j == b:
return (a.index(b))
return -1
print (ser([1,2,3],3))
Alternatively, the loop can be avoided by using in. So, you can actually re-write your method to this:
def ser(a, b):
if b in a:
return a.index(b)
return -1
You are checking to see if item b is in list a, if it is, return the index, otherwise return -1
To take the simplification further, you can actually set this in to a single line in your return:
def ser(a, b):
return a.index(b) if b in a else -1
The else block is executed after the first iteration does not fulfill j == b.
You're better off moving the else block to the for which executes if the item is not found after the for loop is exhausted:
def ser(a,b):
for j in a:
if j == b:
return (a.index(b))
else: # or put default return on this line
return -1
More importantly, You could also check for containment using b in a without needing to iterate through the list.
In the first iteration of the for loop, it will test if the first element in the array is equal to b. It is not, so the code returns -1 immediately, without testing the other elements of the array.
For your case, the correct code is:
def ser(a,b):
for j in a:
if j == b:
return (a.index(b))
return -1
In this way, the code will try all elements in the array, and will return -1 if none of them is equal to b.
You need not to do anything fancy, simple one-liner will work:
def ser(a,b):
return a.index(b) if b in a else -1
# Example
my_list = [1, 2, 3, 4]
ser(my_list, 2)
# returns: 1
ser(my_list, 8)
# returns: -1

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().

How can I add the outcome of a function to a list in python?

def b():
a = int(input("Look up to: ")) // set the range to scan for primes
for num in range(0, a):
if prime(num) == True:
print(num)
print("adding to list")
return num
list = [num]
list.append(num)
else:
print(num, "is not a prime")
So how can I append the outcome to "list" for each new prime?
Forgot to mention the function to check if num is prime:
def prime(num):
for j in range (2, num):
if (num % j) == 0 :
return False
return True
Few points:
Once you return is executed, the value it is applied to is returned to whoever called the function and the code after return never executes.
You're shadowing the built-in function list() which returns a new list by calling a local variable list.
The list is constantly reconstructed by calling [num] which is a shorthand for creating a new list containing only num. What you want to do is update it using append.
Fixing the code, it may look something like:
def get_primes():
a = int(input("Look up to: "))
# 'primes' is a more suitable name for a list of primes
# we're only creating the list *once*, and we're not shadowing 'list'
primes = list()
for candidate in range(0, a):
if prime(candidate) == True:
print(candidate)
print("adding to list")
primes.append(candidate)
else:
print(num, "is not a prime")
# use return to return a result
return primes
You can test this by calling get_primes().
Tip: you could use filter to do the same thing get_primes does:
a = int(input("Look up to: "))
print(filter(prime, range(0, a)))
A minor note about the difference between list and [] is that you can change list's behaviour, which gives finer control, while []'s generated code calls BUILD_LIST directly (harder to change):
>>> dis.dis(lambda: [])
1 0 BUILD_LIST 0
3 RETURN_VALUE
>>> dis.dis(lambda: list())
1 0 LOAD_GLOBAL 0 (list)
3 CALL_FUNCTION 0
6 RETURN_VALUE
It really does not matter in this case, but #Thrustmaster suggested using [] in the comments since it some may see it as cleaner.
Oh, lot of minor syntax errors. Let me list them down..
Python comments do not start with //, but with #. Ref. code line no: 2
list is a keyword in python, you should not use that in your variable declaration. Line ref: 8.
After you do a return, the code after that line will not be executed. Line Ref: 7.
You should not initialize list inside the for loop. It is getting initialized in every iteration.
Instead of if prim(num) == True:, you can simply write if prim(num):.
That said, the correct code should look as follows:
def b():
a = int(input("Look up to: ")) # set the range to scan for primes
primes = [] #Your list
for num in range(0, a):
if prime(num):
print(num)
print("adding to list")
primes.append(num)
else:
print(num, "is not a prime")
return primes
Hope it helps .. :)
Your code looks to be a mix of C and Python (don't use // as comments).
I assume your program is looking for prime numbers up to n. Here is how one might go about implementing this:
import math
def is_prime(n):
if n % 2 == 0 and n > 2:
return False
for i in range(3, int(math.sqrt(n)) + 1, 2):
if n % i == 0:
return False
return True
def find_primes(a, b):
primes = []
for i in range(a, b):
if is_prime(i):
primes.append(i)
return primes
You're almost there. The strange thing about your code is where you've placed the return statement. Try this:
def b():
primesList = []
a = int(input("Look up to: "))
for num in range(0, a):
if prime(num) == True:
print(num)
print("adding to list")
primesList.append(num)
else:
print(num, "is not a prime")
return primesList
Notice that your original return statement would have ended your function early, in fact even before your list would have had the chance to append any prime number at all. The other important point here is that you should never shadow a built-in type (list in this case), or other built-in functions (like map, sorted, etc.).
It's also enough to simply initialize the primesList once and append the num integers inside the for loop.
The other answers are good and address the main issue that you had with rebinding your list variable and failing to return the primes list from function b().
I think it's worth mentioning that a list comprehension can be used to succinctly code the prime list generation:
def prime(num):
for j in range (2, num):
if (num % j) == 0 :
return False
return True
def get_primes(low, high):
return [n for n in range(low, high+1) if prime(n)]
>>> a = input("Look up to: ")
11
>>> get_primes(0, a)
[0, 1, 2, 3, 5, 7, 11]
>>> get_primes(5, a)
[5, 7, 11]
Notes:
Passing the "up to" value into the function is more flexible than
prompting for it in the function.
"Up to" should be inclusive, e.g. get_primes(0, 11) should include 11 in the result. Therefore you need to add one to the upper value when calling range().
Passing low and high allows you to generate primes for arbitrary ranges.
You can wrap the list comprehension with set() to have the result returned as a set.

How can I return false if more than one number while ignoring "0"'s?

This is a function in a greater a program that solves a sudoku puzzle. At this point, I would like the function to return false if there is more then 1 occurrence of a number unless the number is zero. What do am I missing to achieve this?
L is a list of numbers
l =[1,0,0,2,3,0,0,8,0]
def alldifferent1D(l):
for i in range(len(l)):
if l.count(l[i])>1 and l[i] != 0: #does this do it?
return False
return True
Assuming the list is length 9, you can ignore the inefficiency of using count here (Using a helper datastructure - Counter etc probably takes longer than running .count() a few times). You can write the expression to say they are all different more naturally as:
def alldifferent1D(L):
return all(L.count(x) <= 1 for x in L if x != 0)
This also saves calling count() for all the 0's
>>> from collections import counter
>>> def all_different(xs):
... return len(set(Counter(filter(None, xs)).values()) - set([1])) == 0
Tests:
>>> all_different([])
True
>>> all_different([0,0,0])
True
>>> all_different([0,0,1,2,3])
True
>>> all_different([1])
True
>>> all_different([1,2])
True
>>> all_different([0,2,0,1,2,3])
False
>>> all_different([2,2])
False
>>> all_different([1,2,3,2,2,3])
False
So we can break this down into two problems:
Getting rid of the zeros, since we don't care about them.
Checking if there are any duplicate numbers.
Striping the zeros is easy enough:
filter(lambda a: a != 0, x)
And we can check for differences in a set (which has only one of each element) and a list
if len(x) == len(set(x)):
return True
return False
Making these into functions we have:
def remove_zeros(x):
return filter(lambda a: a != 0, x)
def duplicates(x):
if len(x) == len(set(x)):
return True
return False
def alldifferent1D(x):
return duplicates(remove_zeros(x))
One way to avoid searching for every entry in every position is to:
flags = (len(l)+1)*[False];
for cell in l:
if cell>0:
if flags[cell]:
return False
flags[cell] = True
return True
The flags list has a True at index k if the value k has been seen before in the list.
I'm sure you could speed this up with list comprehension and an all() or any() test, but this worked well enough for me.
PS: The first intro didn't survive my edit, but this is from a Sudoku solver I wrote years ago. (Python 2.4 or 2.5 iirc)

Instead of continue, rerun function

I'm wondering how to do the following in Python.
If I have a function with a for loop, it is possible to with an if statement to skip certain numbers.
This is an implementation of fisher-yates d got from activestate.com.
import random
def shuffle(ary):
a=len(ary)
b=a-1
for d in range(b,0,-1):
e=random.randint(0,d)
if e == d:
continue
ary[d],ary[e]=ary[e],ary[d]
return ary
Now continue simply goes to the next value for d. How can I, instead of doing continue, rerun the function with the original parameter ary?
Note that the function is just some example code, I'm curious on how to do this in general.
Also, maintaining a copy of the array might not be possible if the list is big, so thats not really a solution imo.
This is a common recursive pattern. However, your case is a little different than usual because here you need to make a copy of your input list to use when you recurse if the shuffling fails.:
import random
def shuffle(ary):
initial = ary[:]
a=len(ary)
b=a-1
for d in range(b,0,-1):
e=random.randint(0,d)
if e == d:
return shuffle(initial)
ary[d],ary[e]=ary[e],ary[d]
return ary
ary = [1,2,3,4,5,6]
print shuffle(ary)
Also note that Wikipedia gives a (non-recursive) python implementation of the very similar Sattolo's algorithm.
from random import randrange
def sattoloCycle(items):
i = len(items)
while i > 1:
i = i - 1
j = randrange(i) # 0 <= j <= i-1
items[j], items[i] = items[i], items[j]
return
If I read the article correctly, to re-acquire Fisher-Yates, you'd just do one simple change:
from random import randrange
def FisherYates(items):
i = len(items)
while i > 1:
i = i - 1
j = randrange(i+1) # 0 <= j <= i
items[j], items[i] = items[i], items[j]
return
def function(list):
len(list)-1
for i in range(len(list)-1,0,-1):
e= randint(0,i)
while e > i:
e= randint(0,i)
"do something to the list"
return array
?
def function(list):
for i in (a for a in range(len(list)-1,0,-1) if randint(0,a) > a):
#do something with list
#do something else with remainder.
Not exactly what you asked for. Just wanted to remind you of this possibility.
you can copy the parameter to a temp variable. then call the function with the temp variable and use return;
def function(list):
listCopy = list;
len(list)-1
for i in range(len(list)-1,0,-1):
e= randint(0,i)
if e > i:
return function(listCopy)
else
"do something with the list"
return array

Categories