पायथन में एक संख्या के सभी कारकों को खोजने का सबसे कुशल तरीका क्या है?


142

क्या कोई मुझे पायथन (2.7) में एक नंबर के सभी कारकों को खोजने का एक कुशल तरीका समझा सकता है?

मैं ऐसा करने के लिए एक एल्गोरिथ्म बना सकता हूं, लेकिन मुझे लगता है कि यह खराब रूप से कोडित है और बड़ी संख्या के लिए परिणाम तैयार करने में बहुत लंबा समय लेता है।


3
मैं अजगर को नहीं जानता। लेकिन यह पेज शायद आपके लिए उपयोगी हो। enikwipedia.org/wiki/Integer_factorization
स्टैन

3
कैसे उपयोग के बारे में primefac? pypi.python.org/pypi/primefac
Zubo

जवाबों:


265
from functools import reduce

def factors(n):    
    return set(reduce(list.__add__, 
                ([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))

यह सभी कारकों को, बहुत जल्दी, एक संख्या में वापस कर देगा n

वर्गमूल ऊपरी सीमा के रूप में क्यों?

sqrt(x) * sqrt(x) = x। इसलिए यदि दोनों कारक समान हैं, तो वे दोनों वर्गमूल हैं। यदि आप एक कारक को बड़ा बनाते हैं, तो आपको दूसरे कारक को छोटा करना होगा। इसका मतलब है कि दोनों में से एक हमेशा से कम या बराबर होगा sqrt(x), इसलिए आपको केवल दो मिलान कारकों में से एक को खोजने के लिए उस बिंदु तक खोजना होगा। आप तब x / fac1प्राप्त करने के लिए उपयोग कर सकते हैं fac2

की reduce(list.__add__, ...)छोटी सूची ले रहा है[fac1, fac2] और उन्हें एक लंबी सूची में एक साथ शामिल कर रहा है।

[i, n/i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0रिटर्न कारकों की एक जोड़ी है, तो शेष जब आप को विभाजित nछोटे-एक करके है शून्य (यह बहुत बड़ा एक जांच करने की जरूरत नहीं है, यह सिर्फ हो जाता है कि विभाजित करके nछोटे-एक करके।)

set(...)बाहर की दुनिया में डुप्लिकेट है, जो केवल सही वर्गों के लिए होता है से छुटकारा हो रही है। इसके लिए n = 4, यह 2दो बार वापस आ जाएगा , इसलिए setउनमें से एक से छुटकारा मिल जाता है।


1
मैंने अपने कंप्यूटर पर एल्गोरिदम की एक सूची से इसे कॉपी-पेस्ट किया, मैंने जो कुछ किया था, वह था sqrt- यह शायद इससे पहले कि लोग वास्तव में पायथन का समर्थन करने के बारे में सोच रहे थे। 3. मुझे लगता है कि जिस साइट से मैंने इसे लेने की कोशिश की थी, उसके खिलाफ __iadd__था और यह तेज था । मुझे लगता है कि कुछ बिंदु पर x**0.5तेजी से होने के बारे में कुछ याद है sqrt(x)- और यह उस तरह से अधिक मूर्ख है।
एजीएफ़

7
अगर मैं if not n % iइसके बजाय का उपयोग करता है 15% तेजी से प्रदर्शन करने के लिए लगता हैif n % i == 0
dansalmo

3
@sthzg हम चाहते हैं कि यह एक पूर्णांक लौटाए, न कि एक फ्लोट, और पायथन 3 /पर एक फ्लोट लौटाएगा भले ही दोनों तर्क पूर्णांक हों और वे बिल्कुल विभाजन योग्य हों, अर्थात 4 / 2 == 2.0नहीं 2
agf

7
मुझे पता है कि यह एक पुराना सवाल है, लेकिन पायथन 3.x में आपको from functools import reduceयह काम करने के लिए जोड़ना होगा।
गुमनाम

5
@unseen_rider: यह सही नहीं लगता। क्या आप इसे वापस करने के लिए कुछ भी प्रदान कर सकते हैं?
Ry-

55

@Agf द्वारा प्रस्तुत समाधान महान है, लेकिन एक मनमाना विषम के लिए ~ 50% तेजी से चलाने का समय प्राप्त कर सकता है समता के लिए जाँच करके संख्या के । चूंकि विषम संख्या के कारक हमेशा स्वयं विषम होते हैं, इसलिए विषम संख्याओं से निपटने के दौरान इनकी जांच करना आवश्यक नहीं है।

मैंने अभी प्रोजेक्ट यूलर पजल्स को खुद ही हल करना शुरू किया है । कुछ समस्याओं में, एक विभाजक चेक को दो नेस्टेड forछोरों के अंदर कहा जाता है , और इस फ़ंक्शन का प्रदर्शन इस प्रकार आवश्यक है।

एएफएफ के उत्कृष्ट समाधान के साथ इस तथ्य को जोड़ते हुए, मैं इस समारोह के साथ समाप्त हुआ हूं:

from math import sqrt
def factors(n):
        step = 2 if n%2 else 1
        return set(reduce(list.__add__,
                    ([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))

हालांकि, छोटी संख्या (~ <100) पर, इस परिवर्तन से अतिरिक्त ओवरहेड फ़ंक्शन को अधिक समय लग सकता है।

मैंने गति की जांच करने के लिए कुछ परीक्षण चलाए। नीचे कोड का उपयोग किया गया है। विभिन्न भूखंडों का उत्पादन करने के लिए, मैंने X = range(1,100,1)तदनुसार बदल दिया ।

import timeit
from math import sqrt
from matplotlib.pyplot import plot, legend, show

def factors_1(n):
    step = 2 if n%2 else 1
    return set(reduce(list.__add__,
                ([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))

def factors_2(n):
    return set(reduce(list.__add__,
                ([i, n//i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0)))

X = range(1,100000,1000)
Y = []
for i in X:
    f_1 = timeit.timeit('factors_1({})'.format(i), setup='from __main__ import factors_1', number=10000)
    f_2 = timeit.timeit('factors_2({})'.format(i), setup='from __main__ import factors_2', number=10000)
    Y.append(f_1/f_2)
plot(X,Y, label='Running time with/without parity check')
legend()
show()

एक्स = रेंज (1,100,1) एक्स = रेंज (1,100,1)

यहां कोई महत्वपूर्ण अंतर नहीं है, लेकिन बड़ी संख्या के साथ, लाभ स्पष्ट है:

एक्स = रेंज (1,100000,1000) (केवल विषम संख्या) एक्स = रेंज (1,100000,1000) (केवल विषम संख्या)

एक्स = रेंज (2,100000,100) (केवल सम संख्याएँ) एक्स = रेंज (2,100000,100) (केवल सम संख्याएँ)

एक्स = रेंज (1,100000,1001) (वैकल्पिक समता) एक्स = रेंज (1,100000,1001) (वैकल्पिक समता)


28

agf का जवाब वास्तव में काफी अच्छा है। मैं यह देखना चाहता था कि क्या मैं उपयोग करने से बचने के लिए इसे फिर से लिख सकता हूं reduce()। मैंने ये ढूंढ निकाला:

import itertools
flatten_iter = itertools.chain.from_iterable
def factors(n):
    return set(flatten_iter((i, n//i) 
                for i in range(1, int(n**0.5)+1) if n % i == 0))

मैंने एक ऐसे संस्करण की भी कोशिश की, जो मुश्किल जनरेटर कार्यों का उपयोग करता है:

def factors(n):
    return set(x for tup in ([i, n//i] 
                for i in range(1, int(n**0.5)+1) if n % i == 0) for x in tup)

मैंने इसे कंप्यूटिंग द्वारा समयबद्ध किया:

start = 10000000
end = start + 40000
for n in range(start, end):
    factors(n)

मैंने इसे एक बार पाइथन को संकलित करने के लिए चलाया, फिर इसे तीन बार (1) कमांड के तहत चलाया और सबसे अच्छा समय रखा।

  • कम संस्करण: 11.58 सेकंड
  • itertools संस्करण: 11.49 सेकंड
  • मुश्किल संस्करण: 11.12 सेकंड

ध्यान दें कि itertools संस्करण एक tuple का निर्माण कर रहा है और इसे flatten_iter () में पास कर रहा है। यदि मैं इसके बजाय सूची बनाने के लिए कोड बदलता हूं, तो यह थोड़ा धीमा हो जाता है:

  • iterools (सूची) संस्करण: 11.62 सेकंड

मेरा मानना ​​है कि पेचीदा जनरेटर फ़ंक्शंस संस्करण पायथन में सबसे तेज़ संभव है। लेकिन यह वास्तव में कम संस्करण की तुलना में बहुत तेज नहीं है, मेरे माप के आधार पर लगभग 4% तेज है।


2
आप "मुश्किल संस्करण" को सरल कर सकते हैं (अनावश्यक हटाएं for tup in):factors = lambda n: {f for i in range(1, int(n**0.5)+1) if n % i == 0 for f in [i, n//i]}
jfs

11

एगफ के जवाब के लिए एक वैकल्पिक दृष्टिकोण:

def factors(n):    
    result = set()
    for i in range(1, int(n ** 0.5) + 1):
        div, mod = divmod(n, i)
        if mod == 0:
            result |= {i, div}
    return result

1
क्या आप div, mod भाग को समझा सकते हैं?
अदनान

3
divmod (x, y) रिटर्न ((xx% y) / y, x% y), यानी, भागफल और विभाजन का शेष।
c4757p

यह डुप्लिकेट कारकों को अच्छी तरह से संभाल नहीं करता है - उदाहरण के लिए 81 का प्रयास करें।
फकहलर

आपका उत्तर स्पष्ट है, इसलिए मैं इसे गलत समझने के लिए पर्याप्त था। मैं प्राइम फ़ैक्टराइजेशन के बारे में सोच रहा था जहाँ आप कई 3 के कॉल करना चाहते हैं। यह ठीक होना चाहिए, जैसा कि ओपी ने पूछा है।
फकहलर

मैंने सब कुछ एक लाइन में डाला क्योंकि एगफ के जवाब ने ऐसा किया। मुझे यह देखने में दिलचस्पी थी कि क्याreduce() यह काफी तेज था, इसलिए मैंने बहुत कुछ किया reduce(), जिस तरह से एएफएफ ने किया था। पठनीयता के लिए, एक फ़ंक्शन कॉल को is_even(n)एक अभिव्यक्ति की तरह देखना अच्छा होगा n % 2 == 0
स्टीवेहा

9

यहां @ agf के समाधान का विकल्प दिया गया है जो समान एल्गोरिथ्म को अधिक पाइथोनिक शैली में लागू करता है:

def factors(n):
    return set(
        factor for i in range(1, int(n**0.5) + 1) if n % i == 0
        for factor in (i, n//i)
    )

यह समाधान पायथन 2 और पायथन 3 दोनों में बिना किसी आयात के साथ काम करता है और बहुत अधिक पठनीय है। मैंने इस दृष्टिकोण के प्रदर्शन का परीक्षण नहीं किया है, लेकिन asymptotically यह समान होना चाहिए, और यदि प्रदर्शन एक गंभीर चिंता है, तो न तो समाधान इष्टतम है।


7

वहाँ SymPy कहा जाता है में एक उद्योग के शक्ति एल्गोरिथ्म है factorint :

>>> from sympy import factorint
>>> factorint(2**70 + 3**80) 
{5: 2,
 41: 1,
 101: 1,
 181: 1,
 821: 1,
 1597: 1,
 5393: 1,
 27188665321L: 1,
 41030818561L: 1}

इसमें एक मिनट का समय लगा। यह तरीकों के कॉकटेल के बीच स्विच करता है। ऊपर दिए गए दस्तावेज़ देखें।

सभी प्रमुख कारकों को देखते हुए, अन्य सभी कारकों को आसानी से बनाया जा सकता है।


ध्यान दें कि भले ही स्वीकार किए गए उत्तर को उपरोक्त संख्या को कारक करने के लिए लंबे समय तक (यानी एक अनंत काल) चलाने की अनुमति दी गई थी, कुछ बड़ी संख्याओं के लिए यह विफल हो जाएगा, जैसे कि निम्न उदाहरण। यह ढलान के कारण है int(n**0.5)। उदाहरण के लिए, जब n = 10000000000000079**2, हमारे पास है

>>> int(n**0.5)
10000000000000078L

चूंकि 10000000000000079 एक प्राइम है , इसलिए स्वीकृत उत्तर का एल्गोरिथ्म इस कारक को कभी नहीं ढूंढेगा। ध्यान दें कि यह केवल एक ऑफ-बाय-वन नहीं है; बड़ी संख्या के लिए यह अधिक बंद हो जाएगा। इस कारण से इस प्रकार के एल्गोरिदम में फ्लोटिंग-पॉइंट नंबरों से बचना बेहतर है।


2
यह सभी विभाजकों को नहीं ढूँढता है, लेकिन केवल प्रमुख कारक हैं इसलिए यह वास्तव में उत्तर नहीं है। आपको यह दिखाना चाहिए कि अन्य सभी कारकों का निर्माण कैसे किया जा सकता है, न कि यह कहना आसान है! वैसे, इस प्रश्न का उत्तर देने के लिए sympy.divisers एक बेहतर मेल हो सकता है।
कॉलिन पित्रत

और ध्यान दें कि sympy.divisers स्वीकृत समाधान की तुलना में बहुत तेज नहीं है।
कॉलिन पित्रत

@ColinPitrat: मुझे संदेह है कि sympy.divisorsबहुत तेजी से नहीं है, विशेष रूप से कुछ भाजक के साथ संख्याओं के लिए। कोई बेंचमार्क मिला?
Ry-

@ मैंने एक साल पहले यह टिप्पणी लिखी थी। ऐसा लगता है कि एक डबल लिखने के लिए स्वतंत्र महसूस करने के लिए 2 मिनट लगते हैं।
कॉलिन पित्रत

3
@ColinPitrat: जाँच की गई। जैसा कि अपेक्षित था, स्वीकृत उत्तर sympy.divisors100,000 के लिए समान गति के बारे में है और उच्चतर के लिए धीमा (जब गति वास्तव में मायने रखती है)। (और, ज़ाहिर है, sympy.divisorsकी तरह नंबर पर काम करता है 10000000000000079**2।)
Ry-

7

N तक 10 ** 16 (शायद थोड़ा और अधिक) के लिए, यहां एक तेज शुद्ध अजगर 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))

6

आगे और सुधार eryksun के समाधान के लिए। निम्नलिखित भाग का कोड बदले हुए समय विषमता जटिलता को बदलने के बिना सभी कारकों की क्रमबद्ध सूची देता है:

    def factors(n):    
        l1, l2 = [], []
        for i in range(1, int(n ** 0.5) + 1):
            q,r = n//i, n%i     # Alter: divmod() fn can be used.
            if r == 0:
                l1.append(i) 
                l2.append(q)    # q's obtained are decreasing.
        if l1[-1] == l2[-1]:    # To avoid duplication of the possible factor sqrt(n)
            l1.pop()
        l2.reverse()
        return l1 + l2

विचार: क्रमबद्ध सूची प्राप्त करने के लिए list.sort () फ़ंक्शन का उपयोग करने के बजाय जो nlog (n) जटिलता देता है; L2 पर list.reverse () का उपयोग करना बहुत तेज़ है जो O (n) जटिलता लेता है। (यही कारण है कि अजगर बनाया गया है।) एल 2 के बाद। (), एल 2 को कारकों की क्रमबद्ध सूची प्राप्त करने के लिए एल 1 से जोड़ा जा सकता है।

सूचना, l1 में i -s शामिल हैं जो बढ़ रहे हैं। l2 में q -s होते हैं जो कम हो रहे हैं। उपरोक्त विचार का उपयोग करने के पीछे का कारण।


बहुत यकीन list.reverseहै कि O (n) नहीं O (1) है, न कि यह समग्र जटिलता को बदलता है।
एएफएफ

हाँ य़ह सही हैं। मैंने भूल की। O (n) होना चाहिए। (मैंने अब उत्तर को सही एक तक
पहुंचा दिया है

यह @ स्टेवेहा या @ एएफएफ के समाधानों की तुलना में लगभग 2 गुना धीमा है।
6

आप l1 + l2.reversed()जगह में सूची को उलटने के बजाय वापस करके एक छोटी (2-3%) गति में सुधार कर सकते हैं ।
रकौरी

6

मैंने समय के साथ इन अद्भुत उत्तरों में से अधिकांश को अपनी दक्षता बनाम मेरे सरल कार्य की तुलना करने के लिए आजमाया है और फिर भी मैं लगातार उन लोगों को यहां से बाहर निकलने वालों से बेहतर प्रदर्शन करता हूं। मुझे लगा कि मैं इसे साझा करूंगा और देखूंगा कि आप सभी क्या सोचते हैं।

def factors(n):
    results = set()
    for i in xrange(1, int(math.sqrt(n)) + 1):
        if n % i == 0:
            results.add(i)
            results.add(int(n/i))
    return results

जैसा कि लिखा गया है कि आपको परीक्षण करने के लिए गणित आयात करना होगा, लेकिन n ** 5 के साथ math.sqrt (n) को प्रतिस्थापित करना चाहिए। मैं डुप्लिकेट के लिए समय की जाँच व्यर्थ परेशान नहीं करता क्योंकि डुप्लिकेट एक सेट में मौजूद नहीं हो सकता।


उत्तम सामग्री! अगर आप int (math.sqrt (n)) + 1 को लूप के बाहर रखते हैं, तो आपको इसके लिए थोड़ा और प्रदर्शन करना चाहिए, क्योंकि इसे लूप के लिए प्रत्येक पुनरावृत्ति नहीं करना होगा
ट्रिस्टन फॉरवर्ड

3
@TristanForward: यह नहीं है कि पायथन में काम करने वाले लूप कैसे काम करते हैं। xrange(1, int(math.sqrt(n)) + 1)एक बार मूल्यांकन किया जाता है।
Ry-

5

यहां कम किए बिना एक और वैकल्पिक है जो बड़ी संख्या के साथ अच्छा प्रदर्शन करता है। यह sumसूची को समतल करने के लिए उपयोग करता है।

def factors(n):
    return set(sum([[i, n//i] for i in xrange(1, int(n**0.5)+1) if not n%i], []))

1
ऐसा नहीं है, यह असामान्य रूप से द्विघात समय है। एक सूची का उपयोग sumया reduce(list.__add__)समतल करने के लिए न करें ।

4

sqrt(number_to_factor)99 की तरह असामान्य संख्याओं से बड़ी संख्या को पकड़ना सुनिश्चित करें जिसमें 3 * 3 * 11 और है floor sqrt(99)+1 == 10

import math

def factor(x):
  if x == 0 or x == 1:
    return None
  res = []
  for i in range(2,int(math.floor(math.sqrt(x)+1))):
    while x % i == 0:
      x /= i
      res.append(i)
  if x != 1: # Unusual numbers
    res.append(x)
  return res

1
यह एक संख्या के सभी कारकों का उत्पादन नहीं करता है। यह एक संख्या के प्रमुख कारकों की गणना करता है, जैसे कि x=8उम्मीद के लिए:, [1, 2, 4, 8]मिला:[2, 2, 2]
jfs

11 पाया जाता है जब 9 @agf द्वारा दिए गए कोड में कॉमोडेट किया जाता है। `i = 9 -> 99% 9 == 0 -> 9 और 99/9 = 11 जोड़ा जाता है।
स्टाइनर लीमा

4

किसी संख्या के कारक खोजने का सबसे सरल तरीका:

def factors(x):
    return [i for i in range(1,x+1) if x%i==0]

2

यहाँ एक उदाहरण है यदि आप बहुत तेजी से जाने के लिए प्रिम्स नंबर का उपयोग करना चाहते हैं। इन सूचियों को इंटरनेट पर ढूंढना आसान है। मैंने कोड में टिप्पणियाँ जोड़ीं।

# http://primes.utm.edu/lists/small/10000.txt
# First 10000 primes

_PRIMES = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 
        31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 
        73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 
        127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 
        179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 
        233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 
        283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 
        353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 
        419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 
        467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 
        547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 
        607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 
        661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 
        739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 
        811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 
        877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 
        947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 
# Mising a lot of primes for the purpose of the example
)


from bisect import bisect_left as _bisect_left
from math import sqrt as _sqrt


def get_factors(n):
    assert isinstance(n, int), "n must be an integer."
    assert n > 0, "n must be greather than zero."
    limit = pow(_PRIMES[-1], 2)
    assert n <= limit, "n is greather then the limit of {0}".format(limit)
    result = set((1, n))
    root = int(_sqrt(n))
    primes = [t for t in get_primes_smaller_than(root + 1) if not n % t]
    result.update(primes)  # Add all the primes factors less or equal to root square
    for t in primes:
        result.update(get_factors(n/t))  # Add all the factors associted for the primes by using the same process
    return sorted(result)


def get_primes_smaller_than(n):
    return _PRIMES[:_bisect_left(_PRIMES, n)]

मैंने Github पर एक प्रोजेक्ट बनाया: github.com/Pierre-Thibault/Factor
पियरे थिबोल्ट

2

पहले से ही प्रस्तुत किए गए लोगों की तुलना में संभावित रूप से अधिक कुशल एल्गोरिदम (विशेषकर यदि छोटे प्राइमों में हैं n)। यहाँ ट्रिक को उस सीमा तक समायोजित करना है जिसके लिए हर बार अभाज्य कारकों को देखने के लिए ट्रायल डिवीजन की आवश्यकता होती है:

def factors(n):
    '''
    return prime factors and multiplicity of n
    n = p0^e0 * p1^e1 * ... * pk^ek encoded as
    res = [(p0, e0), (p1, e1), ..., (pk, ek)]
    '''

    res = []

    # get rid of all the factors of 2 using bit shifts
    mult = 0
    while not n & 1:
        mult += 1
        n >>= 1
    if mult != 0:
        res.append((2, mult))

    limit = round(sqrt(n))
    test_prime = 3
    while test_prime <= limit:
        mult = 0
        while n % test_prime == 0:
            mult += 1
            n //= test_prime
        if mult != 0:
            res.append((test_prime, mult))
            if n == 1:              # only useful if ek >= 3 (ek: multiplicity
                break               # of the last prime) 
            limit = round(sqrt(n))  # adjust the limit
        test_prime += 2             # will often not be prime...
    if n != 1:
        res.append((n, 1))
    return res

यह निश्चित रूप से अभी भी परीक्षण प्रभाग है और अधिक फैंसी कुछ भी नहीं है। और इसलिए अभी भी इसकी दक्षता में बहुत सीमित है (विशेष रूप से छोटे विभाजकों के बिना बड़ी संख्या के लिए)।

यह अजगर 3 है; विभाजन //केवल एक चीज होनी चाहिए जिसे आपको अजगर 2 (जोड़ from __future__ import division) के लिए अनुकूलित करने की आवश्यकता है ।


1

उपयोग करना set(...)कोड को थोड़ा धीमा कर देता है, और जब आप वर्गमूल की जांच करते हैं, तो यह वास्तव में आवश्यक होता है। यहाँ मेरा संस्करण है:

def factors(num):
    if (num == 1 or num == 0):
        return []
    f = [1]
    sq = int(math.sqrt(num))
    for i in range(2, sq):
        if num % i == 0:
            f.append(i)
            f.append(num/i)
    if sq > 1 and num % sq == 0:
        f.append(sq)
        if sq*sq != num:
            f.append(num/sq)
    return f

if sq*sq != num:जहां वर्गमूल एक पूर्णांक नहीं है, लेकिन वर्गमूल की मंजिल एक कारक है हालत 12, जैसे नंबरों के लिए आवश्यक है।

ध्यान दें कि यह संस्करण अपने आप नंबर वापस नहीं करता है, लेकिन यदि आप इसे चाहते हैं तो यह एक आसान समाधान है। आउटपुट भी सॉर्ट नहीं किया गया है।

मैंने इसे सभी नंबरों पर १०००० बार १-२०० बार और १०० बार सभी नंबरों पर १-५०० बार चला दिया। यह मेरे द्वारा परीक्षण किए गए अन्य सभी संस्करणों को बेहतर बनाता है, जिसमें डैनसल्मो, जेसन शॉर्न्स, ऑक्सोर्क, एगफ्स, स्टेवेहा, और एरिक्सुन के समाधान शामिल हैं, हालांकि ऑक्सक्रो सबसे नजदीक है।


1

आपका अधिकतम कारक आपकी संख्या से अधिक नहीं है, तो, चलिए बताते हैं

def factors(n):
    factors = []
    for i in range(1, n//2+1):
        if n % i == 0:
            factors.append (i)
    factors.append(n)

    return factors

देखा!


1
 import math

    '''
    I applied finding prime factorization to solve this. (Trial Division)
    It's not complicated
    '''


    def generate_factors(n):
        lower_bound_check = int(math.sqrt(n))  # determine lowest bound divisor range [16 = 4]
        factors = set()  # store factors
        for divisors in range(1, lower_bound_check + 1):  # loop [1 .. 4]
            if n % divisors == 0:
                factors.add(divisors)  # lower bound divisor is found 16 [ 1, 2, 4]
                factors.add(n // divisors)  # get upper divisor from lower [ 16 / 1 = 16, 16 / 2 = 8, 16 / 4 = 4]
        return factors  # [1, 2, 4, 8 16]


    print(generate_factors(12)) # {1, 2, 3, 4, 6, 12} -> pycharm output

 Pierre Vriens hopefully this makes more sense. this is an O(nlogn) solution. 

0

निम्नलिखित सूची समझ के रूप में सरल कुछ का उपयोग करें, यह देखते हुए कि हमें 1 और जिस संख्या को हम खोजने की कोशिश कर रहे हैं उसे परखने की आवश्यकता नहीं है:

def factors(n):
    return [x for x in range(2, n//2+1) if n%x == 0]

वर्गमूल के उपयोग के संदर्भ में, हम 10 के कारकों को खोजना चाहते हैं। sqrt(10) = 4इसलिए पूर्णांक के भाग range(1, int(sqrt(10))) = [1, 2, 3, 4]और 4 को स्पष्ट रूप से मिस करने के लिए परीक्षण 5।

जब तक मुझे कुछ याद नहीं आ रहा है, मैं सुझाव दूंगा, अगर आपको इसे इस तरह से करना चाहिए, का उपयोग करके int(ceil(sqrt(x)))। बेशक यह फ़ंक्शन के लिए बहुत सारी अनावश्यक कॉल उत्पन्न करता है।


इस समाधान के साथ मुद्दा यह है कि यह कई संख्याओं की जांच करता है जो संभवतः कारक नहीं हो सकते हैं - और यह प्रत्येक कारक-जोड़ी के उच्च को अलग से जांचता है जब आप पहले से ही जानते हैं कि यह कारक-जोड़ी के छोटे को खोजने के बाद एक कारक है।
agf

1
@ जैसनशोर्ने: जब आप 2 पाते हैं, तो आप तुरंत जानते हैं कि 10/2 = 5 एक भाजक है, साथ ही 5 को अलग से जांचने की आवश्यकता नहीं है! :)
Moberg

0

मुझे लगता है कि पठनीयता और गति के लिए @ ऑक्सीक्रॉस का घोल सबसे अच्छा है, इसलिए यहां अजगर 3+ के लिए फिर से कोड लिखा गया है:

def num_factors(n):
    results = set()
    for i in range(1, int(n**0.5) + 1):
        if n % i == 0: results.update([i,int(n/i)])
    return results

0

जब मैं इस प्रश्न को देखता था तो मुझे बहुत आश्चर्य होता था कि जब कोई खटमल अजगर के छोरों की तुलना में तेज होता है तब भी कोई भी उपयोग नहीं करता है । @ एजीएफ के समाधान को सुन्न के साथ लागू करके और यह तेजी से औसतन 8x निकला । मुझे विश्वास है कि यदि आप सुन्न में कुछ अन्य समाधानों को लागू करते हैं तो आपको आश्चर्यजनक समय मिल सकता है।

यहाँ मेरा कार्य है:

import numpy as np
def b(n):
    r = np.arange(1, int(n ** 0.5) + 1)
    x = r[np.mod(n, r) == 0]
    return set(np.concatenate((x, n / x), axis=None))   

ध्यान दें कि x- अक्ष की संख्याएँ फ़ंक्शंस का इनपुट नहीं हैं। एक्स-माइनस माइनस 1 पर संख्याओं के लिए फ़ंक्शंस का इनपुट 2 है। इसलिए जहां दस का इनपुट होगा 2 ** 10-1- 1023

लूप के बजाय सुन्न का उपयोग करने का प्रदर्शन परीक्षण परिणाम।


1
यदि आप एक पुस्तकालय का उपयोग करने जा रहे हैं, तो यह सही भी बना सकता है: सिम्पी, जैसा कि एवगेनी सर्गेव के जवाब में देखा गया है।
Ry-

0
import 'dart:math';
generateFactorsOfN(N){
  //determine lowest bound divisor range
  final lowerBoundCheck = sqrt(N).toInt();
  var factors = Set<int>(); //stores factors
  /**
   * Lets take 16:
   * 4 = sqrt(16)
   * start from 1 ...  4 inclusive
   * check mod 16 % 1 == 0?  set[1, (16 / 1)]
   * check mod 16 % 2 == 0?  set[1, (16 / 1) , 2 , (16 / 2)]
   * check mod 16 % 3 == 0?  set[1, (16 / 1) , 2 , (16 / 2)] -> unchanged
   * check mod 16 % 4 == 0?  set[1, (16 / 1) , 2 , (16 / 2), 4, (16 / 4)]
   *
   *  ******************* set is used to remove duplicate
   *  ******************* case 4 and (16 / 4) both equal to 4
   *  return factor set<int>.. this isn't ordered
   */

  for(var divisor = 1; divisor <= lowerBoundCheck; divisor++){
    if(N % divisor == 0){
      factors.add(divisor);
      factors.add(N ~/ divisor); // ~/ integer division 
    }
  }
  return factors;
}

लगभग सभी एल्गोरिथ्म यहां सीमा को संख्या * .5 तक सीमित करते हैं, लेकिन वास्तव में यह सीमा बहुत छोटी है। इसकी वास्तव में संख्या का वर्ग। अगर हमारे पास कम विभाजक हैं तो हम उसे आसानी से ऊपरी तौर पर प्राप्त कर सकते हैं। इसकी बस संख्या / भाजक के बाद से। 16 के लिए मुझे sqrt के लिए 4 मिलता है, फिर 1 से 4 तक लूप मिलता है। 2 के बाद से 16 का निचला बंटवारा है। मैं यह मुख्य कारक के बारे में सीखते हुए आया, इसलिए मुझे नहीं पता कि यह कहीं और प्रकाशित होता है, लेकिन यह बड़ी संख्या के लिए भी काम करता है। मैं एक अजगर समाधान प्रदान कर सकता हूं।
तंगंग अतांग

-4

मुझे लगता है यह ऐसा करने का सबसे सरल तरीका है:

    x = 23

    i = 1
    while i <= x:
      if x % i == 0:
        print("factor: %s"% i)
      i += 1

आपका जवाब, सही परिणाम देने के दौरान, बहुत अक्षम है। स्वीकार किए गए उत्तर पर एक नजर है। यह कैसे हल करता है इसका स्पष्टीकरण हमेशा एक उत्तर को अधिक उपयोगी बनाने में मदद करता है।
निक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.