What is the recursive call (or inductive steps) for a function that returns the number of integers from 1 to N, which evenly divide N. The idea is to concieve a pure recursive code in python for this function. No 'for' or 'while' loops, neither modules can be used. The function num_of_divisors(42) returns 8, representing 1, 2, 3, 6, 7, 14, 21, and 42 as divisors of 42.
def num_of_divisors(n):
return sum(1 if n % i==0 else 0 for i in range(((n+1)**0.5)//1)
Good luck explaining it to your teacher!
If you really can't use for loops (?????????) then this is impossible without simulating one.
def stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num=1):
"""I had to copy this from Stack Overflow because it's such an
inane restriction it's actually harmful to learning the language
"""
if loop_num <= (n+1) ** 0.5:
if n % loop_num == 0:
return 2 + \
stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num+1)
else:
return stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num+1)
else:
if n % loop_num == 0:
return 1
Bonus points: explain why you're adding 2 in the first conditional, but only 1 in the second conditional!
Here you go buddy your teacher'll be happy.
def _num_of_divisors(n, k):
if (k == 0):
return 0
return _num_of_divisors(n, k-1) + (n % k == 0)
def num_of_divisors(n):
return _num_of_divisors(n, n)
It's easier than you think to convert such a simple problem from a loop to a recursive function.
Start with a loop implementation:
n = 42
result = []
for i in range(n+1):
if n % i == 0:
result.append(i)
then write a function
def num_of_divisors_helper(i, n, result):
if <condition when a number should be added to result>:
result.append(n)
# Termination condition
if <when should it stop>:
return
# Recursion
num_of_divisors_helper(i+1, n, result)
Then you define a wrapper function num_of_divisors that calls num_of_divisors_helper. You should be able to fill the gaps in the recursive function and write the wrapper function yourself.
It's a simple, inefficient solution, but it matches your terms.
Without using %
def is_divisible(n, i, k):
if k > n:
return False
if n - i*k == 0:
return True
else:
return is_divisible(n, i, k+1)
def num_of_divisors(n, i=1):
if i > n/2:
return 1
if is_divisible(n, i, 1):
return 1 + num_of_divisors(n, i+1)
else:
return num_of_divisors(n, i+1)
num_of_divisors(42) -> 8
def n_divisors(n,t=1):
return (not n%t)+(n_divisors(n,t+1) if t < n else 0)
good luck on the test later ... better hit those books for real, go to class and take notes...
with just one input i guess
t=0
def n_divisors(n):
global t
t += 1
return (not n%t)+(n_divisors(n) if t < n else 0)
Related
I have the following recursive function to get the mth term of a n-bonacci sequence as shown below this question. My problem is that the use of for and while loops is totally banned from the code, so I need to get rid off
for i in range(1, n+1):
temp += n_bonacci(n,m-i)
and convert the code into something that is not a loop but nevertheless achieves the same effect. Among the things I can use, but this is not an exclusive enumeration, is: (1) use built-in functions like sum() and .join() and (2) use list comprehensions.
The full code is as follows:
def n_bonacci(n,m): #n is the number of n initial terms; m is the mth term.
if (m < n-1):
return 0
elif (m == n-1):
return 1
else:
temp = 0
#[temp += n_bonacci(n,m-i) for i in range(n)] #this is an attempt at using list comprehension
for i in range(1, n+1):
temp += n_bonacci(n,m-i)
return temp
print("n_bonacci:",n_bonacci(2,10))
print("n_bonacci:",n_bonacci(7,20))
Here's a solution that avoids any type of loop, including loops hidden inside comprehensions:
def n_bonacci_loopless(n, m):
def inner(i, c):
if i == m:
return sum(c)
else:
return inner(i+1, c[-(n-1):] + [sum(c)])
if m < n-1:
return 0
elif (m == n-1):
return 1
else:
return inner(n, [0] * (n-1) + [1])
The base cases are the same, but for recursive cases it initialises a list of collected results c with n-1 zeroes, followed by a one, the sum of which would be the correct answer for m == n.
For m > n, the inner function is called again as long as i < m, summing the list and appending the result to the end of the last n-1 elements of the list so far.
If you are allowed to use comprehensions, the answer is trivial:
def n_bonacci(n,m):
if (m < n-1):
return 0
elif (m == n-1):
return 1
else:
return sum(n_bonacci(n, m-i) for i in range(1, n+1))
You can rewrite the code as follows using list comprehensions:
def n_bonacci(n,m): #n is the number of n initial terms; m is the mth term.
if (m < n-1):
return 0
elif (m == n-1):
return 1
else:
return sum(n_bonacci(n, m-i) for i in range(1, n + 1))
print("n_bonacci:",n_bonacci(2,10))
print("n_bonacci:",n_bonacci(7,20))
To go beyond #Grismar 's answer you can write your own version of sum which doesn't use loops.
def n_bonacci_loopless(n, m):
def recsum(l, s=0):
return recsum(l[1:], s + l[0])
def inner(i, c):
if i == m:
return recsum(c)
else:
return inner(i+1, c[-(n-1):] + [recsum(c)])
if m < n-1:
return 0
elif (m == n-1):
return 1
else:
return inner(n, [0] * (n-1) + [1])
I am just getting started in Python Programming. I had a problem on checking if a given list contains alternating sequence of primes and perfect squares. The list can start with either a prime or a perfect square. I came up with a solution but it's not efficient as it generates unwanted lists. Is this possible with more efficient Python code?
First I'm creating functions to generate a list of primes as well as perfect squares up to the max value of testing list. Functions squaretest() and primecheck():
def squaretest(num):
sqlist=[]
i=1
while i**2 <= num:
sqlist.append(i**2)
i+=1
return sqlist
def primecheck(num):
primelist=[]
for i in range(2,num + 1):
for p in range(2,i):
if (i % p) == 0:
break
else:
primelist.append(i)
return primelist
Then I am dividing the given list into lists of even index and odd index elements and checking all elements of them against the primelist and the squarelist:
def primesquare(l):
if len(l)==1:
primelist = primecheck(l[0])
sqlist = squaretest(l[0])
return (l[0] in primelist) or (l[0] in sqlist)
else:
ol=[]
el=[]
for i in range(0,len(l),2):
ol.append(l[i])
for p in range (1, len(l),2):
el.append(l[p])
primelist = primecheck(max(l))
sqlist = squaretest (max(l))
return((all(x in primelist for x in el)) == True and (all(y in sqlist for y in ol)) == True) or ((all(x in primelist for x in ol)) == True and (all(y in sqlist for y in el)) == True)
It works.
Any suggestions will be really helpful.
You can use sets to check if all members of a list are in another list.
def primesquare(l):
if len(l) == 0:
return True
primelist = set(primecheck(max(l)))
sqlist = set(squaretest(max(l)))
ol = set(l[::2])
el = set(l[1::2])
odds_are_primes = ol.issubset(primelist)
odds_are_squares = ol.issubset(sqlist)
evens_are_primes = el.issubset(primelist)
evens_are_squares = el.issubset(sqlist)
return (odds_are_primes and evens_are_squares) or (odds_are_squares and evens_are_primes)
I came up with a solution but it's not efficient as it generates
unwanted lists.
Assuming the unwanted lists are the two lists representing the even and odd elements, then we can fix that. (Eliminating the primes and squares list is a whole 'nother problem.) Below is my rework of your code -- we don't create addtional lists but rather with a couple of reusable ranges which are objects that produce integer sequences as needed, but not stored in memory.
Your any() design is efficient in that the arguments are generator expressions, not lists, which are computed as needed. As soon as a flaw is found in the array, the whole thing stops and returns False--it doesn't need to process the rest:
def squares(number):
return {x * x for x in range(int(number ** 0.5) + 1)}
def primes(number):
prime_set = set()
for i in range(2, number + 1):
for p in range(2, int(i ** 0.5) + 1):
if (i % p) == 0:
break
else: # no break
prime_set.add(i)
return prime_set
def primesquare(array):
if not array:
return True # define as the problem demands
length, maximum = len(array), max(array)
odd, even = range(0, length, 2), range(1, length, 2)
prime_set, square_set = primes(maximum), squares(maximum)
return all(array[i] in prime_set for i in even) and all(array[i] in square_set for i in odd) or all(array[i] in prime_set for i in odd) and all(array[i] in square_set for i in even)
I admire #AndreySemakin's set-based solution (+1), and use sets above, but his solution generates the same lists you want to eliminate (just in the form of sets).
I came up with this solution:
def primesquare(lst):
# checking if the first element is either perfect square or a prime
if not lst or (not checksquare(lst[0]) and not checkprime(lst[0])):
return False
length = len(lst)
if length == 1:
return True
if checksquare(lst[0]):
# if first element is square then make s(quare)=2 and p(rime)=1
s, p = 2, 1
else:
# if first element is prime then make s=1 and p=2
s, p = 1, 2
# running perfect square loop from s to len-1 with gap of 2 and checking condition
for i in range(s, length, 2):
if not checksquare(lst[i]):
return False
# running prime loop from p to len-1 with gap of 2
for i in range(p, length, 2):
if not checkprime(lst[i]):
return False
return True
def checksquare(n): # function to check perfect square
if n < 0:
return False
if 0 <= n <= 1:
return True
for i in range(int(n ** 0.5) + 1):
if i * i == n:
return True
return False
def checkprime(n): # function to check prime
if n < 2:
return False
if n % 2 == 0:
return n == 2
for i in range(3, int(n ** 0.5) + 1, 2):
if n % i == 0:
return False
return True
Hi I'm fairly new to python and trying to create a Fibonacci calculator function that prints all values up to a given number, if the number entered is not in the sequence then it adds the next Fibonacci number to the list. For example, if 10 is entered it should return [0, 1, 1, 2, 3, 5, 8, 13]. The function has to be recursive. Here is my current code:
def fibonacci(n):
n = int(n)
# The nested sub_fib function computes the Fibonacci sequence
def sub_fib(n):
if n < 2:
return n
else:
return (sub_fib(n-1) + sub_fib(n-2))
#This aspect of the main fib function applies the condition if the number
# input is not in the sequence then it returns the next value up
fib_seq= [sub_fib(i) for i in range(0,n) if sub_fib(i)<=n]
if fib_seq[-1] < n:
fib_seq.append(fib_seq[-1] + fib_seq[-2])
return fib_seq
else:
return fib_seq
print(fibonacci(input("Input a number to print sequence up to: ")))
I've managed to get it to work but it is incredibly slow (I assume due to the recursion) is there anyway I can speed it up without massively changing the program?
The two main reasons why your program is slow:
you calculate each Fibonacci number separately, you do not reuse the effort you have invested in finding the previous number;
you calculate the first n Fibonacci numbers, but from the moment the condition fails, you can stop.
You can change the program to still be recursive, but reuse the work to compute the previous number, and stop from the moment you have constructed the list.
You simply have to use the following function:
def fibon(a,b,n,result):
c = a+b
result.append(c)
if c < n:
fibon(b,c,n,result)
return result
and we initialize it with: fibon(0,1,n,[]). In each iteration, it will calculate the next Fibonacci number c = a+b and append it to the result. In case that number is still smaller than c < n then we need to calculate the next number and thus perform the recursive call.
def fibonacci(n):
n = int(n)
def fibon(a,b,n,result):
c = a+b
result.append(c)
if c < n:
fibon(b,c,n,result)
return result
return fibon(0,1,n,[])
print(fibonacci(input("Input a number to print sequence up to: ")))
This uses recursion but much faster than naive recursive implementations
def fib(n):
if n == 1:
return [1]
elif n == 2:
return [1, 1]
else:
sub = fib(n - 1)
return sub + [sub[-1] + sub[-2]]
Here are some examples of how you can improve the speed:
"""
Performance calculation for recursion, memoization, tabulation and generator
fib took: 27.052446
mem_fib took: 0.000134
tabular_fib took: 0.000175
yield_fib took: 0.000033
"""
from timeit import timeit
LOOKUP_SIZE = 100
number = 30
lookup = [None] * LOOKUP_SIZE
def fib(n):
return 1 if n <= 2 else fib(n - 1) + fib(n - 2)
def mem_fib(n):
"""Using memoization."""
if n <= 2:
return 1
if lookup[n] is None:
lookup[n] = mem_fib(n - 1) + mem_fib(n - 2)
return lookup[n]
def tabular_fib(n):
"""Using Tabulation."""
results = [1, 1]
for i in range(2, n):
results.append(results[i - 1] + results[i - 2])
return results[-1]
def yield_fib(n):
"""Using generator."""
a = b = 1
yield a
yield b
while n > 2:
n -= 1
a, b = b, a + b
yield b
for f in [fib, mem_fib, tabular_fib, yield_fib]:
t = timeit(stmt=f"f({number})", number=10, globals=globals())
print(f"{f.__name__} took: {t:.6f}")
In an online class, I received this problem.
Write a function numDivisors( N ) that returns the number of integers from 1 to N (inclusive) that divide N evenly. For example, numDivisors(42) would return 8, since 1, 2, 3, 6, 7, 14, 21, and 42 are divisors of 42. (Python 2.7)
Although I have solved it with a loop, I'm wondering how I would go about this with recursion.
The basic functionality of this function with a loop would be:
def numDivisors( N ):
""" returns # of integers that divide evenly into N """
divisors = 1 # the factor 1
if N != 1:
divisors += 1 # the factor N
for i in range(2,int(N)): # loops through possible divisors
if N % i == 0: # factor found
divisors += 1
return divisors
How could I implement it recursively using the bare basics (declaration, conditionals, looping, etc. up to list comprehensions)?
Thanks!
If we have to be recursive:
>>> def ndiv(N, i=1):
... return 1 if N==i else ((N % i == 0) + ndiv(N, i+1))
...
Let's test it. As per the question:
For example, numDivisors(42) would return 8
>>> ndiv(42)
8
Thus, this produces the desired output.
If we can do away with recursion, here is how to do it just using list comprehension:
>>> def div(N):
... return sum(1 for i in range(1, N+1) if N % i == 0)
...
>>> div(42)
8
how about
def find_divisors(N,i=1):
if i >= N**0.5+1: return set([])
if N%i == 0: return set([i,N//i]).union(find_divisors(N,i+1))
return find_divisors(N,i+1)
recursion is a pretty lousy solution to this problem ... do you really need to find all the divisors? or are you looking for a special one?
I need to write a recursive function, which finds the least common multiple elements of the list with n length.
My code:
import random
def random_num(n):
return [random.randint(-20,20) for i in range(n)]
def gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a % b)
def my_nok(n,m):
return (n/gcd(n,m))*m
The first problem is: my functions work only with two arguments, not with the whole list.
The second problem: i need to have the only one function for finding the least common multiple (my code contains two for that).
You need something to recur through a list, such as the following. If there are 2 elements in the list, do your normal LCM. If it's longer, then recur on the list tail, and then do LCM with that result and the first element.
def lcm(in_list):
if len(in_list) == 2:
# Do your normal LCM computation here
else:
return lcm([in_list[0], lcm(in_list[1:]))
you need to find to LCM of the whole list. let "l" be the LCM of the whole array and if we pick any 2 random numbers from array, they will have a LCM say "l1" and so on and so forth "l2","l3","l4".... the LCM of these will also be the LCM of the whole array.
# we can find LCM of two numbers by the basic prime factorizing method
# but i will use the idea that GCD(a,b) * LCM(a,b) = a*b
# and it is easy to find the GCD(a,b)=[GCD(a,a%b)or GCD(b,b%a)] depending on if a is bigger or b
# i have used this idea because factoring large numbers take time.
so my idea is you can use divide and conquer
def LCM_of_array(array):
if len(array)==2:
return LCM(a,b)
else:
return LCM( LCM_of_array(n[0:len(array)/2]) , LCM_of_array(n[len(array)/2:len(array)])
you can explicitly define LCM(a,b) or just add a few more line of codes in this only
Edit: Code
def nod(a, b): #to find GCD
if b == 0:
return a
else:
if a>b:
return nod(b, a % b)
else:
return nod(a,b%a)
def nok(a, b): #to find LCM of two numbers
return a * b / nod(a, b)
def nok_of_array(n): #function for LCM of array
if len(n) == 2:
return nok(n[0], n[1])
else:
return nok (nok_of_array(n[ 0:len(n)/2 ]) , nok_of_array( n [ len(n)/2 : len(n)]))
My code, the last return doesn't work correct.
import random
def nod(a, b):
if b == 0:
return a
else:
return nod(b, a % b)
def nok(a, b):
return a * b / nod(a, b)
def nok_of_array(n):
if len(n) == 2:
return nok(n[1], n[2])
else:
return nok(nok_of_array[0:len(n)/2], nok_of_array[len(n)/2:len(n)])
n = [random.randint(-20,20) for i in range(0, random.randint(1, 20))]
print(nok_of_array(n))
print(n)
Here is a solution I could work out and it worked for me.
def findDivisor(number):
if number%2 == 0:
return 2
elif number%3==0:
return 3
return number
def LCM(nums):
lcm = 1
while len(nums) > 0:
minOfnums = min(nums)
divisor = findDivisor(minOfnums)
for x in range(0, len(nums)):
Quotient = nums[x]/divisor
Reminder = nums[x]%divisor
if Reminder == 0:
nums[x] = Quotient
lcm*=divisor
minOfnums = min(nums)
if minOfnums == 1:
nums.remove(minOfnums)
return lcm