I'm trying to memoize divisor sums of numbers.
divisorSums = {}
def sumDivisors(num):
global divisorSums
total = 0
if num == 1:
return 0
for i in xrange(num/2, 0, -1):
if i in divisorSums:
return divisorSums[i]
else:
if not num % i:
total += i
divisorSums[num] = total
return total
However, this returns 1 for all numbers, when I loop through the numbers. It is correct when it used singularly, so the problem is my lookup system. I'm pretty sure I don't understand how to look for a value in a dictionary. Can someone help me out?
The usual shortcut trick for memoize is to use a mutuable default argument
def sumDivisors(num, divisorSums={}):
if num in divisorSums: # Check if you have
return divisorSums[num] # memoized the answer here
total = 0
if num == 1:
return 0
for i in xrange(num/2, 0, -1):
if not num % i:
total += i
divisorSums[num] = total
return total
Other than that your code seems to work ok. How were you runnning it to get just 1?
Here:
if i in divisorSums:
return divisorSums[i]
returning divisorSums[i] is not the right thing to do as there may be some prime factors less than i. Here is one way using a helper function to remember/calculate factors of numbers:
from itertools import groupby
divisorC={}
def divisors(num):
if num in divisorC:
return divisorC[num]
l = {1:1}
for i in xrange(num/2, 1, -1):
if num % i == 0:
l[i] = 1
l.update(divisors(i))
l.update(divisors(num/i))
break
divisorC[num] = l
return divisorC[num]
def sumDivisors(num):
if num == 1: return 0
l = {}
for i in xrange(num/2, 0, -1):
if num % i == 0:
l.update(divisors(i))
l.update(divisors(num/i))
l[i] = 1
l[num/i] = 1
break
return sum(v for v in l)
Related
I have code so far which gets me the factors of a number, however I need the amount of factors in any number inputted. How can I do that?
def factor(n):
factor_values = []
for i in range(1, n + 1):
if n % i == 0:
factor_values.append(i)
values = ""
for v in factor_values:
values += str(v) + " "
return values
I have tried to find how many factors does a value have using python, I think because your code using list to save all the factors, you can count all the item using print(factor_values.len()) which will return the length of a list.
Does it solve your problem?
def factor(n):
factor_values = []
for i in range(1, n + 1):
if n % i == 0:
factor_values.append(i)
return len(factor_values)
If you want to find the factors of numbers without 1 and the number itself, then:
def factor(n):
factor_values = []
for i in range(2, n):
if n % i == 0:
factor_values.append(i)
return len(factor_values)
Or in another way you can just count the factors:
def factor(n):
count = 0
for i in range(2, n):
if the_num % i == 0:
count += 1
return count
I am trying to perform a Collatz algorithm on the following code. It works fine when I use a range of 1-10 etc... However, if the range is for example 1-500,000 it's too slow and won't ever show me the output of the longest sequence.
numberArray = []
s=int(1)
f=int(10)
def collatz(n):
global count
if n == 1:
count += 1
numberArray.append(count)
return True
elif (n % 2) == 0:
count += 1
collatz(n/2)
else:
count += 1
collatz(3*n+1)
for i in range (s, f+1):
count = 0
ourNumber = i
collatz(i)
print(max(numberArray))
Stef means something like this, which uses a dictionary to memorise the values that have already been counted:
s = 1
f = 10000000
def collatz(n):
if n in collatz.memory:
return collatz.memory[n]
if (n % 2) == 0:
count = collatz(n//2)+1
else:
count = collatz((3*n+1)//2)+2
collatz.memory[n] = count
return count
collatz.memory = {1:0}
highest = max(collatz(i) for i in range(s, f+1))
highest_n = max(collatz.memory, key=collatz.memory.get)
print(f"collatz({highest_n}) is {highest}")
Output:
collatz(8400511) is 685
Use lru_cache decorator. Its function to memorize (cache) the returned value of function called with specific argument.
Also read how to write clean code in python
The next code solves your problem
from functools import lru_cache
number_array = []
s = 1
f = 500000
#lru_cache
def collatz(n: int):
if n == 1:
return 1
elif n % 2 == 0:
return 1 + collatz(n // 2)
else:
return 1 + collatz(3 * n + 1)
for i in range(s, f + 1):
number_array.append(collatz(i))
print(number_array)
I'm a new at programming, I like solving this euler questions and I know there are solutions for this problem but it's not about the problem at all actually.
So, i managed to create a working function for finding example: 33. triangular number. It works but i couldn't manage to properly desing my while loop. I wanted to make it like, it starts from first triangular checks it's divisors make list of it's divisors, checks the length of the divisors, because problem wants "What is the value of the first triangle number to have over five hundred divisors?" . But i never managed to work the while loop. Thank you for reading.
nums = [1]
triangles = [1]
divisors = []
def triangularcreator(x):
if x == 1:
return 1
n = 1
sum = 0
while n!=0:
n += 1
nums.append(n)
for i in range(len(nums)):
sum += nums[i]
triangles.append(sum)
sum = 0
if x == len(triangles):
n = 0
return triangles[-1]
counter = 1
while True:
for i in range(1, triangularcreator(counter) + 1):
if triangularcreator(counter) % i == 0:
divisors.append(i)
if len(divisors) == 500:
print(triangularcreator(counter))
break
counter +=1
divisors.clear()
You should try to change a few things, starting with calculating just once the value of triangularcreator(counter) and assigning this value to a variable that you can use in different points of your code.
Second, you create a loop which will be calculate always triangularcreator(1). At the end of each iteration you increase the value of counter+=1, but then at the beginign of the new iteration you assignt it again value 1, so it will not progress as you expect. Try this few things:
counter = 1
while True:
triangle = triangularcreator(counter)
for i in range(1, triangle + 1):
if triangle % i == 0:
divisors.append(i)
if len(divisors) == 500:
print(triangle )
break
counter +=1
Also these two arrays nums = [1], triangles = [1] should be declared and initialized inside the def triangularcreator. Otherwise you would be appending elements in each iteration
Edit: I believe it is better to give you my own answer to the problem, since you are doing some expensive operations which will make code to run for a long time. Try this solution:
import numpy as np
factor_num = 0
n = 0
def factors(n):
cnt = 0
# You dont need to iterate through all the numbers from 1 to n
# Just to the sqrt, and multiply by two.
for i in range(1,int(np.sqrt(n)+1)):
if n % i == 0:
cnt += 1
# If n is perfect square, it will exist a middle number
if (np.sqrt(n)).is_integer():
return (cnt*2)-1
else:
return (cnt*2)-1
while factor_num < 500:
# Here you generate the triangle, by summing all elements from 1 to n
triangle = sum(list(range(n)))
# Here you calculate the number of factors of the triangle
factor_num = factors(triangle)
n += 1
print(triangle)
Turns out that both of your while loop are infinite either in triangularcreatorin the other while loop:
nums = [1]
triangles = [1]
divisors = []
def triangularcreator(x):
if x == 1:
return 1
n = 1
sum = 0
while n:
n += 1
nums.append(n)
for i in range(len(nums)):
sum += nums[i]
triangles.append(sum)
sum = 0
if len(triangles) >= x:
return triangles[-1]
return triangles[-1]
counter = 1
while True:
check = triangularcreator(counter)
for i in range(1, check + 1):
if check % i == 0:
divisors.append(i)
if len(divisors) >= 500:
tr = triangularcreator(counter)
print(tr)
break
counter +=1
Solution
Disclaimer: This is not my solution but is #TamoghnaChowdhury, as it seems the most clean one in the web. I wanted to solve it my self but really run out of time today!
import math
def count_factors(num):
# One and itself are included now
count = 2
for i in range(2, int(math.sqrt(num)) + 1):
if num % i == 0:
count += 2
return count
def triangle_number(num):
return (num * (num + 1) // 2)
def divisors_of_triangle_number(num):
if num % 2 == 0:
return count_factors(num // 2) * count_factors(num + 1)
else:
return count_factors((num + 1) // 2) * count_factors(num)
def factors_greater_than_triangular_number(n):
x = n
while divisors_of_triangle_number(x) <= n:
x += 1
return triangle_number(x)
print('The answer is', factors_greater_than_triangular_number(500))
In this function, I want to return a value when the if statement is executed.
Since Python always returns something, it returns None.
def Persistence(number, counter):
numArr = [int(i) for i in str(number)]
result = 1
data = None
for j in numArr:
result *= j
if len(str(number)) == 1:
data = str(f'Done. {counter} steps taken')
print(data)
# return data
else:
counter = counter + 1
Persistence(result, counter)
# return data
print(Persistence(333,0))
Maybe I put the return keyword in the wrong place (I checked by putting it in two different places, marked as a comment) or something else, but I couldn't figure it out.
Please help me out. Also, if there is another way to count the recursion steps besides my technique, please let me know.
Maybe try this :
def Persistence(number, counter):
numArr = [int(i) for i in str(number)]
result = 1
for j in numArr:
result *= j
if len(str(number)) == 1:
return str(f'Done. {counter} steps taken')
counter = counter + 1
return Persistence(result, counter)
print(Persistence(333,0))
Hope it helps
The issue is that you're not setting the value from the else call to persistence to anything. The following code return the data value for me:
def Persistence(number, counter):
numArr = [int(i) for i in str(number)]
result = 1
data = None
for j in numArr:
result *= j
if len(str(number)) == 1:
data = str(f'Done. {counter} steps taken')
print(data)
return data
else:
counter = counter + 1
data = Persistence(result, counter)
return data
x = Persistence(333, 0)
Then if we print x:
print(x)
# Done. 3 steps taken
Your logic to count the recursion steps is basically correct, you just need to place the return statements for both the:
1)Base case
2)The recursive call itself
The following modification to your code will do the trick of what you are asking:
def Persistence(number, counter):
numArr = [int(i) for i in str(number)]
result = 1
data = None
for j in numArr:
result *= j
if len(str(number)) == 1:
data = str(counter)
return data
else:
counter = counter + 1
return Persistence(result, counter)
print(Persistence(333,0))
The above code will return the output of:
3
Please note that the reason you were getting "None" as the output in your original code is because you were not making a return at the actual recursive call itself: **return** Persistence(result, counter)
So when you ran print(Persistence(333,0)) it was returning nothing resulting in the None.
This question is better to learn about recursion than you may think. But we won't muddy the waters by mixing recursion (functional style) with statements and side effects (imperative style).
It looks like you're trying to calculate multiplicative root and persistence. Instead of putting all concerns of the computation into a single function, break it down into sensible parts -
def digits (n = 0):
if n < 10:
return [ n ]
else:
return digits (n // 10) + [ n % 10 ]
def product (n = 0, *more):
if not more:
return n
else:
return n * product (*more)
def mult_root (n = 0):
if n < 10:
return [ n ]
else:
return [ n ] + mult_root (product (*digits (n)))
def mult_persistence (n = 0):
return len (mult_root (n)) - 1
print (mult_persistence (333))
# 3
print (mult_root (333))
# [ 333, 27, 14, 4 ]
I am trying to list all the factors of a number called count. Whenever I run it, it returns 1. For example: if 6 = count, then what should be returned when calling findFactor(6) is 1 2 3 6. What is returned is 1
divisors = ""
def findFactor(count):
divisors = ""
valueD = 0
for i in range(1, count+1):
valueD = count/i
if isinstance(valueD,int) == True:
divisors = str(valueD)+" "
print divisors
This can be done on one line using list comprehension.
def factorize(num):
return [n for n in range(1, num + 1) if num % n == 0]
You can refer this code:
def find_factor(n):
factor_values = []
for i in range(1, n + 1):
if n % i == 0:
factor_values.append(i)
values = ""
for v in factor_values:
values += str(v) + " "
return values
The function will return 1 2 3 6
First of all, you have an indentation error. print divisors need to be tabbed to inside the for-loop.
divisors = ""
def findFactor(count):
divisors = ""
valueD = 0
for i in range(1, count+1):
valueD = count/i
if isinstance(valueD,int) == True:
divisors = str(valueD)+" "
print divisors
Furthermore like #juanpa.arrivillaga mentioned, your results will vary between Python 2 and Python 3.
However, if you want your divisors to print in the order you want, i.e. start with 1 you need to change your range to for i in range(count,0, -1). You will get multiple 1's , but that's something I'll leave for you to figure out. A little challenge, if you will. ;)
This is the total code I have come up with. Thank you for all the help.
def findFactor(n):
factorValues = []
for i in range(1, n + 1):
if n % i == 0:
factorValues.append(i)
values = ""
for v in factorValues:
values += str(v) + " "
print values.count(" ")
# prints the number of factors
print values
findFactor(21)
It will print the number of factors, and then the factors on the next line.
The answers given so far are all brute force methods.
For n=10000, they will have to iterate ten thousand times.
The following will iterate only 100 times:
def find_factors(n):
factors = []
i = 1
j = n
while True:
if i*j == n:
factors.append(i)
if i == j:
break
factors.append(j)
i += 1
j = n // i
if i > j:
break
return factors
If there were a list of prime numbers available, it could be made even faster.