первый вопрос здесь. Я пытаюсь изучить python, перейдя через эйлер проекта, и я столкнулся с контрольно-пропускным пунктом. Следующий метод (возвращает список простых факторов) отлично подходит для одного вызова:
def findPrimeFactors(num, primeFactors = []):
'''Find the prime factors of an arbitrary positive integer
input: num to factorize
returns: a list containing the prime factors of the number
'''
pIndex = 2
while (num >= pIndex):
if num % pIndex == 0:
num /= pIndex
primeFactors.append(pIndex)
return FindPrimes.findPrimeFactors(num, primeFactors)
else:
pIndex += 1
return primeFactors
Однако, когда я использую его в цикле, например (этот метод может быть еще не завершен, в настоящее время он приводит к бесконечному циклу, поскольку больше простых чисел не может быть найдено):
def countPrimes(n = 1001):
'''find n amount of unique primes ascending
input: number of primes to find
returns: list of n primes starting from 2 '''
primes = []
i = 2
while len(primes) < n:
primeFactors = FindPrimes.findPrimeFactors(i)
print(primeFactors) #verify method behavior
if len(primeFactors) is 1:
primes.append(primeFactors[0])
i += 1
return primes
В результате первый цикл возвращает [2], следующий возвращает [2, 3] и т.д., добавляя новые результаты в список, который я Wanted был пуст при первом рекурсивном вызове. Кажется, мой список сохраняется, но я точно не знаю, почему? Я читаю класс и списки классов Python, который дает мне некоторые подсказки, но рекурсия усложняет его больше.
Рекурсивный также означает, что я не могу просто назначить ему пустое множество. Исходя из фона C++, я ожидал, что переменная primeFactors должна быть повторно инициализирована каждый раз, когда функция вызывается из моей программы. Тем не менее здесь есть детская змея.
EDIT: Это итеративная версия findPrimeFactors, которую я написал. Я знаю, что это не оптимально, но я хотел бы хотя бы сделать его достаточно эффективным, чтобы соответствовать правилу Project Euler 1 минута. Любые предложения по улучшению или ясности оцениваются.
PRIMES = [2,3,5,7,11,13,17,19]
import math
class FindPrimes():
'''V2 iterative'''
def findPrimeFactors(n, primeFactors = None):
'''Find the prime factors of an arbitrary positive integer
input: num to factorize
returns: a list containing the prime factors of the number
'''
if primeFactors is None:
primeFactors = []
num = n
ceil = math.sqrt(n) #currently unused
global PRIMES
knownPrimes = PRIMES
#check known primes for divisors first, then continue searching for primes by brute force
while True:
factorFound = False
for prime in knownPrimes:
if num % prime == 0:
primeFactors.append(prime)
num /= prime
factorFound = True
break #ensure that the list returned has ascending primes
if not factorFound:
break
#once attempts have been made to reduce using known primes
#search for new primes if the number is not fully reduced
i = knownPrimes[-1] + 2
while num != 1:
if num % i == 0:
knownPrimes.append(i)
primeFactors.append(i)
num /= i
i += 2
return primeFactors
def countPrimes(n = 10001):
'''find n amount of unique primes ascending
input: number of primes to find
returns: list of n primes starting from 2 '''
primes = []
i = 2
while len(primes) < n:
primeFactors = FindPrimes.findPrimeFactors(i)
if len(primeFactors) == 1:
primes.append(primeFactors[0])
#print(primeFactors[-1])
i += 1
print(len(primes))
return primes
nth = 10001
print(FindPrimes.countPrimes(nth)[nth-1]) #print the largest prime found
Как упоминалось hammar, значение по умолчанию создается только один раз, когда функция определена и разделяется между вызовами.
Обычный способ заключается в использовании значения маркера по умолчанию:
def findPrimeFactors(num, primeFactors=None):
if primeFactors is None:
primeFactors = []
...
Off-, но ваша функция findPrimeFactor()
будет возвращаться один раз для каждого найденного множителя. Python не выполняет удаление хвостового вызова, поэтому вам, вероятно, следует переписать его с помощью итерации вместо рекурсии.
Значение по умолчанию primeFactors
разделяется между вызовами, поэтому при его изменении он остается неизменным для будущих вызовов.
Пример:
def foo(bar = []):
bar.append(1)
return bar
print foo()
print foo()
Вывод:
[1]
[1, 1]
Вы должны вернуть новый список вместо изменения значения по умолчанию:
def foo(bar = []):
return bar + [1]
print foo()
print foo()
Вывод:
[1]
[1]