why doesn't memoization work in this Python code? - python

i am following a dynamic programming video. However the memoization for my code is not working. It is not storing any True/False when i print(memo) it is blank. Please advise
def cansum(targetsum,numbers):
memo = dict()
print(memo)
# check in memory
if targetsum in memo:
return memo[targetsum]
if targetsum < 0: return False
if targetsum == 0: return True
for number in numbers:
remainder = targetsum - number
if cansum(remainder,numbers) == True:
memo[targetsum] = True
return True
memo[targetsum] = False
return False
print(cansum(7,[2,3])) #True
print(cansum(7,[5,3,4,7])) #True

I think this is what you might want to do:
def cansum(targetsum, numbers):
memo = dict()
def cansum_helper(targetsum, numbers):
# check in memory
if targetsum in memo:
return memo[targetsum]
if targetsum < 0:
return False
if targetsum == 0:
return True
for number in numbers:
remainder = targetsum - number
if cansum_helper(remainder, numbers) == True:
memo[targetsum] = True
return True
memo[targetsum] = False
return False
result = cansum_helper(targetsum, numbers)
print(memo)
return result
print(cansum(7, [2, 3])) # True
print(cansum(7, [5, 3, 4, 7])) # True
If you put
memo = dict()
into recursive function, you are creating one dict for every recursive function, and once the memo is set, the return statement follows, so you won't be able to see changes. But what is intended is that you only need one dict for your whole function.

Related

Python: Recursive Function. How to return all subsets of targetsum

My code is not showing the shortest subset eg [7] or it is not reading all the subsets, [7], [3,4] to return the shortest subset. Can explain why only 1 set of result is return and how should I modify it to show all subset? Thanks
Image of Code that i wanted to follow as below
def howsum(targetsum,numbers,combo=None):
if combo == None:
combo = list()
if targetsum == 0: return [ ]
if targetsum < 0: return None
shortcombo = None
for number in numbers:
remainder = targetsum - number
combo = howsum(remainder,numbers,combo)
if combo != None:
combo.append(number)
if shortcombo == None or len(shortcombo) > len(combo):
shortcombo = combo
return shortcombo
return shortcombo
print(howsum(7,[4,3,7]))
Wrote code that closely matches the original JavaScript.
Although JavaScript names will work, I refactored function and variable names to agree with Python style, namely:
Function names should be lowercase, with words separated by underscores as necessary to improve readability.
Variable names follow the same convention as function names.
Code
def best_sum(target_sum, numbers):
if target_sum == 0: return []
if target_sum < 0: return None
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers)
if remainder_combination != None:
combination = [*remainder_combination, num] # Python * equivalent to JavaSscript ...
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
return shortest_combination
Test
print(bestSum(7, [3, 4, 7])) # Output: [7]
Using Memoization (i.e. caching)
def best_sum(target_sum, numbers, memo = None):
if memo is None:
memo = {0:[]}
if target_sum < 0:
return None
if target_sum in memo:
return memo[target_sum]
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers, memo)
if remainder_combination != None:
combination = [*remainder_combination, num] # Python * equivalent to JavaSscript ...
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
memo[target_sum] = shortest_combination
return memo[target_sum]
print(best_sum(7, [3, 4, 7])) # Output: 7
# Following very slow on non-memoized version
print(best_sum(100,[10,1,25])) # Output: [25, 25, 25, 25]
I am not sure about this but while defining a function in python and giving 2 sets of codes it is not actually performing the second set of the code when calling out the function. I got the same problem with some other project. And I got no answers but saying I did some wrong in the code!!!
Added memoization, however with 1 inside sets of num. the results gone haywire.
def best_sum(target_sum, numbers,memo=None):
if memo == None:
memo = dict()
if target_sum in memo:
return memo[target_sum]
if target_sum == 0: return []
if target_sum < 0: return None
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers,memo)
if remainder_combination != None:
remainder_combination.append(num)
combination = remainder_combination
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
memo[target_sum] = shortest_combination
return shortest_combination
print(best_sum(100,[5,1,25]))
This code by answer posted by DarylG works. By changing the .append to [*list,var] However I dont understand why is the result different between function append and *
def best_sum(target_sum, numbers,memo=None):
if memo == None:
memo = dict()
if target_sum in memo:
return memo[target_sum]
if target_sum == 0: return []
if target_sum < 0: return None
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers,memo)
if remainder_combination != None:
combination = [*remainder_combination,num] #this line from append to *
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
memo[target_sum] = shortest_combination
return shortest_combination
print(best_sum(100,[5,1,25]))
I checked out your code. What I felt missing was
Incorrect placement of return and storing the values inside of combo (set
instead of list).
def howsum(targetsum,numbers,combo=None):
if combo == None:
combo = set()
if targetsum == 0:
return [ ]
if targetsum < 0:
return None
for idx,number in enumerate(numbers):
remainder = targetsum - number
if howsum(remainder,numbers[idx:],combo) != None:
combo.add(number)
else:
return combo
return None
print(howsum(7,[7,3,4,2,5]))
Hope this helps. While this gives you a solution I would recommend using a different way to solve such issues (twoSum solutions) or two pointer approach with O(n).
In addition to using memo/any variable for memoization, you can employ functools.lru_cache method. Just remember to typecast the input while testing.
import functools
#functools.lru_cache(maxsize=4)
def howsum(targetnum, num_list):
if targetnum == 0:
return []
if targetnum < 0:
return None
for num in num_list:
rem = targetnum - num
rem_val = howsum(rem, num_list)
if rem_val is not None:
rem_val.append(num)
return rem_val
return None
print(howsum(7, tuple([5, 3, 4, 7])))
print(howsum(8, tuple([3, 4, 2])))
print(howsum(300, tuple([7, 14])))

Python - function returns true when a given number is a prime number or else false

Hi I'm a beginner and I'm stuck on this question that wants me to use only while loop to solve. The question wants me to write a function that returns True when the given number is a prime number and it returns False if the given number is not a prime number.
My code so far:
def is_prime(n):
i = 2
while i <= n//2:
if n%i != 0:
return True
else:
return False
i+=1
The problem I have is I think my code displays the correct output for numbers 4 and above and it returns 'None' for 1, 2, and 3. I've debugged it and I think the problem is the while loop condition. But I don't know how to fix it. I would appreciate it if any of you pros can help me out!
edit:
I changed the while condition but 1 still returns None.. and 2 returns False when it's supposed to return True
def is_prime(n):
i = 2
while i <= n:
if n%i != 0:
return True
else:
return False
i+=1
import math;
def is_prime(n):
i = 2
while i < max(math.sqrt(n),2):
if n%i != 0:
return True
else:
return False
if i == 2:
i+=1
else
i+=2
You could hard-code these 3 cases, in case you dont want to use sqrt:
def is_prime(n):
i = 2
if n in (1,3):
return True
elif n == 2:
return False
while i <= n//2:
if n%i != 0:
return True
else:
return False
i+=1
for x in range(1, 5):
print(x, '=', is_prime(x))
Output:
(1, '=', True)
(2, '=', False)
(3, '=', True)
(4, '=', False)
Want to get really fancy? Make a Sieve of Eratosthenes:
def is_prime(n):
a = list()
# Assume all are prime
a[0:n+1] = (n+1)*[1]
# Start with removing even numbers
i = 2
while i*i <= n:
print ("I: ", i)
# Set all divisible by i to 0
a[0:n+1:i] = len(a[0:n+1:i])*[0]
# If a[n] is zero, return False
if a[n] == 0:
return False
# Increment i until we have a prime number
while a[i] == 0:
i+=1
if a[n] == 0:
return False
else:
return True
If you want to impress your lesson teacher you can show him a fast probabilistic prime number isprime for numbers larger than 2**50. I haven't found any errors in it after weeks of cpu time stress testing it on a 6 core AMD:
import random
import math
def lars_last_modulus_powers_of_two(hm):
return math.gcd(hm, 1<<hm.bit_length())
def fast_probabilistic_isprime(hm):
if hm < 2**50:
return "This is to only be used on numbers greater than 2**50"
if lars_last_modulus_powers_of_two(hm+hm) != 2:
return False
if pow(2, hm-1, hm) == 1:
return True
else:
return False
def fast_probabilistic_next_prime(hm):
if hm < 2**50:
return "This is to only be used on numbers greater than 2**50"
if hm % 2 == 0:
hm = hm + 1
hm += 2
while fast_probabilistic_isprime(hm) == False:
hm += 2
return hm
""" hm here is bitlength, which must be larger than 50.
usage is create_probabilistic_prime(1000)
"""
def create_probabilistic_prime(hm):
if 2**hm < 2**50:
return "This is to only be used on numbers greater than 2**50"
num = random.randint(2**hm,2**(hm+1))
return fast_probabilistic_next_prime(num)

Writing a function which accepts two strings and returns True in python 3

Write a python function, check_anagram() which accepts two strings and returns True, if one string is an anagram of another string. Otherwise returns False.
The two strings are considered to be an anagram if they contain repeating characters but none of the characters repeat at the same position. The length of the strings should be the same.
Note: Perform case insensitive comparison wherever applicable.
This is my code:
def check_anagram(data1,data2):
first = data1.lower()
second = data2.lower()
d1 = []
d2 = []
for i in range(0, len(first)):
d1.append(first[i])
for i in range(0, len(second)):
d2.append(second[i])
for_check1 = sorted(d1)
for_check2 = sorted(d2)
if (for_check1 != for_check2):
return False
count = 0
if (len(d1) == len(d2)):
for i in d1:
for j in d2:
if(i == j):
a = d1.index(i)
b = d2.index(j)
if(a == b):
return False
else:
count += 1
if(count == len(first)):
return True
else:
return False
print(check_anagram("Schoolmaster", "Theclassroom"))
The output I am getting is "False"
Although this program is giving relevant output for string values like {silent, listen}{Moonstarrer, Astronomer}{apple, mango} but not for the above two strings(in code)
What cases am I missing in this code?? How to rectify this thing?
Your function could be simplified as:
def check_anagram(data1, data2):
data1 = data1.lower()
data2 = data2.lower()
if sorted(data1) != sorted(data2):
return False
return all(data1[i] != data2[i] for i in range(len(data1)))
Which actually works for the case you specified.
your code is correct just write len(second) instead of count.
def check_anagram(data1,data2):
first = data1.lower()
second = data2.lower()
d1 = []
d2 = []
for i in range(0, len(first)):
d1.append(first[i])
for i in range(0, len(second)):
d2.append(second[i])
for_check1 = sorted(d1)
for_check2 = sorted(d2)
if (for_check1 != for_check2):
return False
count = 0
if (len(d1) == len(d2)):
for i in d1:
for j in d2:
if(i == j):
a = d1.index(i)
b = d2.index(j)
if(a == b):
return False
else:
count += 1
if(len(second) == len(first)):
return True
else:
return False
print(check_anagram("Schoolmaster", "Theclassroom"))
This program of mine is clearing all possible test cases.
def check_anagram(data1,data2):
data1=data1.lower()
data2=data2.lower()
if(len(data1)==len(data2)):
if(sorted(data1)!=sorted(data2)):
return False
else:
if(data1[i]!=data2[i] for i in range(len(data1))):
return True
else:
return False
else:
return False
print(check_anagram("eat","tea"))

'None' is printed when I want 'True' for input 5

In this primality test program, 'None' is printed when I input a prime, instead of 'True'. How can I get it to print 'True'?.
def main():
import math
def check_n(n):
n_s = int(math.sqrt(n))
for i in range(2, n_s):
if (n_s % i) == 0:
return False
break
else:
return True
def msg():
n = int(input('Enter a number, I will return True if it is a prime'))
return n
print(check_n(msg()))
main()
You need to change int(math.sqrt(n)) to int(math.sqrt(n)+1), because range runs until n_s-1. So if the input is 5, range(2,int(math.sqrt(5))) is just range(2,2), which is empty.
In addition, you need to take the return True outside of the for loop, otherwise your code may stop in a too early stage. You also don't need the break statement after return False (the function will never arrive to that line, as it will return False if it enters to that if statement).
Finally, change if (n_s % i) == 0: to if (n % i) == 0:, as you need to check if n is divisible by i (and not its square root).
Here is a more clean version:
import math
def check_n(n):
n_s = int(math.sqrt(n)+1)
for i in range(2, n_s):
if (n % i) == 0:
return False
return True
def msg():
n = int(input('Enter a number, I will return True if it is a prime'))
return n
print(check_n(msg()))
First: Your break statement is redundant.
Second: For values such as 3 the for loop is never executing because value
n_s is less than 2 and since the for loop isn't executing the
python is returning the default value None(which is returned when
no value is specified).
Hence your check_n(n) function has to be
def check_n(n):
n_s = int(math.sqrt(n))
for i in range(2, n_s + 1):
if (n_s % i) == 0:
return False
return True
one liner :
check_n = lambda n : sum([i for i in range(2, int(math.sqrt(n)+1)) if n % i == 0]) == 0
don't overcomplicate things ..
Your range is (2,2) or None when you choose anything less than 9.
So to solve your first problem: add 2 to n_s (for input 3)
You also have a problem with your logic.
Your for loop should be checking that n mod i is 0, not n_s.
This should work:
def main():
import math
def check_n(n):
n_s = int(math.sqrt(n)+1)
for i in range(2, n_s):
if (n % i) == 0:
return False
return True
def msg():
n = int(input('Enter a number, I will return True if it is a prime'))
return n
print(check_n(msg()))
main()

create two functions in python

i have these task which i believe i have done well to some level
Create a function get_algorithm_result to implement the algorithm below
1- Get a list of numbers L1, L2, L3....LN as argument
2- Assume L1 is the largest, Largest = L1
3- Take next number Li from the list and do the following
4- If Largest is less than Li
5- Largest = Li
6- If Li is last number from the list then
7- return Largest and come out
8- Else repeat same process starting from step 3
Create a function prime_number that does the following
Takes as parameter an integer and
Returns boolean value true if the value is prime or
Returns boolean value false if the value is not prime
so i came up with this code below
def get_algorithm_result(my_list):
if not any(not type(y) is int for y in my_list):
largest = 0
for item in range(0,len(my_list)):
if largest < my_list[item]:
largest = my_list[item]
return largest
else:
return(my_list[-1])
def prime_number(integer):
if integer%2==0 and 2!=integer:
return False
else:
return True
get_algorithm_result([1, 78, 34, 12, 10, 3])
get_algorithm_result(["apples", "oranges", "mangoes", "banana", "zoo"])
prime_number(1)
prime_number(78)
prime_number(11)
for the question above, there is a unittes which reads
import unittest
class AlgorithmTestCases(unittest.TestCase):
def test_maximum_number_one(self):
result = get_algorithm_result([1, 78, 34, 12, 10, 3])
self.assertEqual(result, 78, msg="Incorrect number")
def test_maximum_number_two(self):
result = get_algorithm_result(["apples", "oranges", "mangoes", "banana", "zoo"])
self.assertEqual(result, "zoo", msg="Incorrect number")
def test_prime_number_one(self):
result = prime_number(1)
self.assertEqual(result, True, msg="Result is invalid")
def test_prime_number_two(self):
result = prime_number(78)
self.assertEqual(result, False, msg="Result is invalid")
def test_prime_number_three(self):
result = prime_number(11)
self.assertEqual(result, True, msg="Result is invalid")
but once i run my code ,it returns error saying
Test Spec Failed
Your solution failed to pass all the tests
what is actually wrong with my code?
Here is the solution..
def get_algorithm_result(num_list):
largest =num_list[0]
for item in range(0,len(num_list)):
if largest < num_list[item]:
largest = num_list[item]
return largest
def prime_number(integer):
if integer == 1:
return False
elif integer == 3:
return True
if integer > 3:
for i in range(3, (integer-1)):
if integer % i == 0:
return False
else:
return True
This should help for the prime
def prime_number(integer):
if integer == 1: return True
if integer == 2: return True
if integer == 3: return True
if integer % 2 == 0: return False
if integer % 3 == 0: return False
else: return True

Categories

Resources