Voici la manière très stupide:
def divisorGenerator(n):
for i in xrange(1,n/2+1):
if n%i == 0: yield i
yield n
Le résultat que je voudrais obtenir est similaire à celui-ci, mais je voudrais un algorithme plus intelligent (celui-ci est trop lent et stupide :-)
Je peux trouver les facteurs premiers et leur multiplicité assez rapidement. J'ai un générateur qui génère un facteur de cette façon:
(facteur1, multiplicité1)
(facteur2, multiplicité2)
(facteur3, multiplicité3)
etc...
c'est-à-dire la sortie de
for i in factorGenerator(100):
print i
est:
(2, 2)
(5, 2)
Je ne sais pas à quel point est-ce utile pour ce que je veux faire (je l'ai codé pour d'autres problèmes), de toute façon, je voudrais une façon plus intelligente de faire
for i in divisorGen(100):
print i
afficher ceci:
1
2
4
5
10
20
25
50
100
UPDATE: Merci beaucoup à Greg Hewgill et à sa "façon intelligente":) Calculer tous les diviseurs de 100000000 a pris 0.01s avec son chemin contre les 39s que la manière stupide a pris sur ma machine, très cool:
UPDATE 2: Cesser de dire que ceci est une copie de this post. Le calcul du nombre de diviseurs d'un nombre donné n'a pas besoin de calculer tous les diviseurs. C'est un problème différent, si vous pensez que ce n'est pas le cas, cherchez «fonction de diviseur» sur Wikipedia. Lisez les questions et la réponse avant de poster, si vous ne comprenez pas quel est le sujet, n’ajoutez pas de réponses inutiles et déjà données.
Étant donné votre fonction factorGenerator, voici un divisorGen qui devrait fonctionner:
def divisorGen(n):
factors = list(factorGenerator(n))
nfactors = len(factors)
f = [0] * nfactors
while True:
yield reduce(lambda x, y: x*y, [factors[x][0]**f[x] for x in range(nfactors)], 1)
i = 0
while True:
f[i] += 1
if f[i] <= factors[i][1]:
break
f[i] = 0
i += 1
if i >= nfactors:
return
L'efficacité globale de cet algorithme dépendra entièrement de l'efficacité du factorGenerator.
Pour développer ce que Shimi a dit, vous ne devriez exécuter votre boucle que de 1 à la racine carrée de n. Ensuite, pour trouver la paire, faites n / i
, et cela couvrira tout l'espace du problème.
Comme il a également été noté, il s’agit d’un problème NP ou «difficile». La recherche exhaustive, telle que vous la faites, est à peu près aussi bonne qu'elle obtient des réponses garanties. Ce fait est utilisé par les algorithmes de chiffrement et autres pour les sécuriser. Si quelqu'un devait résoudre ce problème, la plupart, sinon toutes les communications «sécurisées» actuelles seraient rendues non sécurisées.
Code python:
import math
def divisorGenerator(n):
large_divisors = []
for i in xrange(1, int(math.sqrt(n) + 1)):
if n % i == 0:
yield i
if i*i != n:
large_divisors.append(n / i)
for divisor in reversed(large_divisors):
yield divisor
print list(divisorGenerator(100))
Ce qui devrait sortir une liste comme:
[1, 2, 4, 5, 10, 20, 25, 50, 100]
Bien qu'il y ait déjà beaucoup de solutions à cela, je dois vraiment poster ça :)
Celui-ci est:
Code:
def divisors(n):
# get factors and their counts
factors = {}
nn = n
i = 2
while i*i <= nn:
while nn % i == 0:
factors[i] = factors.get(i, 0) + 1
nn //= i
i += 1
if nn > 1:
factors[nn] = factors.get(nn, 0) + 1
primes = list(factors.keys())
# generates factors from primes[k:] subset
def generate(k):
if k == len(primes):
yield 1
else:
rest = generate(k+1)
prime = primes[k]
for factor in rest:
prime_to_i = 1
# prime_to_i iterates prime**i values, i being all possible exponents
for _ in range(factors[prime] + 1):
yield factor * prime_to_i
prime_to_i *= prime
# in python3, `yield from generate(0)` would also work
for factor in generate(0):
yield factor
Je pense que vous pouvez vous arrêter à math.sqrt(n)
au lieu de n/2.
Je vais vous donner un exemple afin que vous puissiez le comprendre facilement. Maintenant, la sqrt(28)
est 5.29
donc ceil(5.29)
sera 6. Donc, si je vais m'arrêter à 6 heures, je pourrai obtenir tous les diviseurs. Comment?
Tout d'abord voir le code et ensuite voir l'image:
import math
def divisors(n):
divs = [1]
for i in xrange(2,int(math.sqrt(n))+1):
if n%i == 0:
divs.extend([i,n/i])
divs.extend([n])
return list(set(divs))
Maintenant, voir l'image ci-dessous:
Disons que j'ai déjà ajouté 1
à ma liste de diviseurs et que je commence par i=2
, donc
Donc, à la fin de toutes les itérations car j'ai ajouté le quotient et le diviseur à ma liste, tous les diviseurs de 28 sont remplis.
J'espère que cela t'aides. Si vous avez des doutes n'hésitez pas à revenir en arrière et je me ferai un plaisir de vous aider :).
Source: Comment déterminer les diviseurs d'un nombre
Rayon de cercle - Code et image
J'aime la solution de Greg, mais j'aimerais que ce soit plus en python, comme… .. Je pense que ce serait plus rapide et plus lisible; donc après un certain temps de codage, je suis sorti avec ceci.
Les deux premières fonctions sont nécessaires pour créer le produit cartésien des listes. Et peut être réutilisé quel que soit le problème. Au fait, je devais programmer moi-même, si quelqu'un connaissait une solution standard à ce problème, n'hésitez pas à me contacter.
"Factorgenerator" renvoie maintenant un dictionnaire. Et puis le dictionnaire est introduit dans les "diviseurs", qui l'utilisent pour générer d'abord une liste de listes, où chaque liste est la liste des facteurs de la forme p ^ n avec p prime . Ensuite, nous créons le produit cartésien. de cette liste, et nous avons finalement utilisé la solution de Greg pour générer le diviseur . Nous les avons triés et renvoyés.
Je l'ai testé et il semble être un peu plus rapide que la version précédente. Je l'ai testé dans le cadre d'un programme plus important, donc je ne peux pas vraiment dire à quel point c'est plus rapide.
Pietro Speroni (pietrosperoni)
from math import sqrt
##############################################################
### cartesian product of lists ##################################
##############################################################
def appendEs2Sequences(sequences,es):
result=[]
if not sequences:
for e in es:
result.append([e])
else:
for e in es:
result+=[seq+[e] for seq in sequences]
return result
def cartesianproduct(lists):
"""
given a list of lists,
returns all the possible combinations taking one element from each list
The list does not have to be of equal length
"""
return reduce(appendEs2Sequences,lists,[])
##############################################################
### prime factors of a natural ##################################
##############################################################
def primefactors(n):
'''lists prime factors, from greatest to smallest'''
i = 2
while i<=sqrt(n):
if n%i==0:
l = primefactors(n/i)
l.append(i)
return l
i+=1
return [n] # n is prime
##############################################################
### factorization of a natural ##################################
##############################################################
def factorGenerator(n):
p = primefactors(n)
factors={}
for p1 in p:
try:
factors[p1]+=1
except KeyError:
factors[p1]=1
return factors
def divisors(n):
factors = factorGenerator(n)
divisors=[]
listexponents=[map(lambda x:k**x,range(0,factors[k]+1)) for k in factors.keys()]
listfactors=cartesianproduct(listexponents)
for f in listfactors:
divisors.append(reduce(lambda x, y: x*y, f, 1))
divisors.sort()
return divisors
print divisors(60668796879)
P.S. c'est la première fois que je publie sur stackoverflow. Je suis impatient de recevoir vos commentaires.
Adapté de CodeReview , voici une variante qui fonctionne avec num=1
!
from itertools import product
import operator
def prod(ls):
return reduce(operator.mul, ls, 1)
def powered(factors, powers):
return prod(f**p for (f,p) in Zip(factors, powers))
def divisors(num) :
pf = dict(prime_factors(num))
primes = pf.keys()
#For each prime, possible exponents
exponents = [range(i+1) for i in pf.values()]
return (powered(primes,es) for es in product(*exponents))
Voici un moyen intelligent et rapide de le faire pour des nombres allant jusqu’à 10 ** 16 environ en pur Python 3.6,
from itertools import compress
def primes(n):
""" Returns a list of primes < n for n > 2 """
sieve = bytearray([True]) * (n//2)
for i in range(3,int(n**0.5)+1,2):
if sieve[i//2]:
sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
return [2,*compress(range(3,n,2), sieve[1:])]
def factorization(n):
""" Returns a list of the prime factorization of n """
pf = []
for p in primeslist:
if p*p > n : break
count = 0
while not n % p:
n //= p
count += 1
if count > 0: pf.append((p, count))
if n > 1: pf.append((n, 1))
return pf
def divisors(n):
""" Returns an unsorted list of the divisors of n """
divs = [1]
for p, e in factorization(n):
divs += [x*p**k for k in range(1,e+1) for x in divs]
return divs
n = 600851475143
primeslist = primes(int(n**0.5)+1)
print(divisors(n))
Ancienne question, mais voici ma position:
def divs(n, m):
if m == 1: return [1]
if n % m == 0: return [m] + divs(n, m - 1)
return divs(n, m - 1)
Vous pouvez utiliser un proxy avec:
def divisorGenerator(n):
for x in reversed(divs(n, n)):
yield x
Remarque: pour les langues qui prennent en charge, cela peut être récursif.
Je vais juste ajouter une version légèrement révisée d'Anivarth (car je crois que c'est la plus Pythonique) pour référence future.
from math import sqrt
def divisors(n):
divs = {1,n}
for i in range(2,int(sqrt(n))+1):
if n%i == 0:
divs.update((i,n//i))
return divs
Voici ma solution. Cela semble être stupide mais fonctionne bien ... et j'essayais de trouver tous les diviseurs appropriés afin que la boucle commence à i = 2.
import math as m
def findfac(n):
faclist = [1]
for i in range(2, int(m.sqrt(n) + 2)):
if n%i == 0:
if i not in faclist:
faclist.append(i)
if n/i not in faclist:
faclist.append(n/i)
return facts
En supposant que la fonction factors
renvoie les facteurs de n (par exemple, factors(60)
renvoie la liste [2, 2, 3, 5]), voici une fonction permettant de calculer les diviseurs de n :
function divisors(n)
divs := [1]
for fact in factors(n)
temp := []
for div in divs
if fact * div not in divs
append fact * div to temp
divs := divs + temp
return divs
Si vous ne vous souciez que d'utiliser des listes de compréhension, rien ne vous importe!
from itertools import combinations
from functools import reduce
def get_devisors(n):
f = [f for f,e in list(factorGenerator(n)) for i in range(e)]
fc = [x for l in range(len(f)+1) for x in combinations(f, l)]
devisors = [1 if c==() else reduce((lambda x, y: x * y), c) for c in set(fc)]
return sorted(devisors)