简体   繁体   中英

Loop construct in Python

I'm a python noob and have issues setting up a loop that checks if an int z is divisible by a set of numbers, eg by 1 - 10. I wrote the following code snippets, but they all return X =[all the numbers of z]... ie they fail to apply the if condition so that the mod is checked over all n in a given range/set.

X = []
z = 1
while z in range(1,1000):
    if all(z % n == 0 for n in range(1,21)):
        X.append(z) 
    z += 1

also tried:

X = []
if all(i % n == 0 for n in range(1,21)):
    X.append(i)

and

X = []
for z in range(1,1000000):
    if all(z % n == 0 for n in range(1,21)):
        X.append(z)  

Any idea what's going wrong in each of these (or at least 1) of these cases? Thanks for the help!

EDIT: was wrong, fixed answer.

Are you using numpy? There is something funny going on with numpy and it's version of all.

import numpy as np
all( z % n for n in range(1,5)) # NameError
np.all( z % n for n in range(1,5)) # True
z = 5
all( z % n for n in range(1,5)) # False
np.all( z % n for n in range(1,5)) # True
np.all([z % n for n in range(1,5)) # False

The problem isn't with Python but with your math. x % n == x if x is less than n. In particular, no integer less than 21 can be zero mod every number up to 21. 3 % 18 is 3. So you need to rethink what you're asking. If you really try to find a number that is evenly divisible by every number from 1 to 21, the only numbers you'll get will be huge numbers (eg, 21!).

print [z for z in range(10000) if all(z%k==0 for k in range(1,10))]
>>> [0, 2520, 5040, 7560]

seems to work. Second example, i doesn't seem to be initialized. Third seems to work.

PS : beware that fact(21) is quite big and certainly bigger than 1000000 - it's not a perfect result but it might be a factor or two below the first answer (prime decomposition yadda yadda)

In your first example you're doing some strange combination of a while and for loop, and I was sort of surprised it runs at all!

In the second example you're not initializing or updating i .

The third example works. However, the first number that's divisible by all numbers from 1 to 20 is 232792560, which is outside your range.

As an alternative you could also do it in one line

X = [z for z in range(1, 1000000) if all(z % n == 0 for n in range(1, 21))]

but again, you won't get any results below 232792560!

First off, all numbers are divisible by ONE, even zero. So your range(1,21) should probably exclude 1 by being range(2,21)

x % 1 == 0 

is always True if x > 0 and is an integer.

Then to clarify: if you have:

rangeOne = range(1,1000000)
rangeTwo = range(2,21)

Secondly are you looking only for numbers in rangeOne that are divisible by all numbers in rangeTwo?

Or are you looking for subset of possible primes from rangeOne such that you want to get a list of numbers that are not divisible by any number in rangeTwo (with a resultant integer verse a fraction)?

Or the inverse of that, all numbers from rangeOne that can be divisible by any one or more numbers in rangeTwo, meaning to exclude primes.

There are more cases like that.

Well first of all, the set that actually needs to check any int z for divisibility is smaller than N for the range 1-N . Here is why: Any number x that is divisible by 6, is also divisible by it's factors ie 1,2,3,6 .

So essentially, your algorithm is :

for number in rangeArray:
     removeSubList(getAllFactors(number),rangeArray)

Translation into python code:

#Note: this can be sped up even faster by appending both the multiples 
#at the same time instead of iterating over the range 1,number
#Note: get_all_factors(6) will return [1,2,3] but not [1,2,3,6]
def get_all_smaller_factors(number):
   factors = [number,1] 
   for x in range(1,number):
       if (number % x == 0 and number not in factors):
           factors.append(x)
   return factors


#Note: again, I'm too tired to find proper names, please improve later.
def min_factor_list(max):
    factors = range(1,max)
    for factor in factors:
        #remove the sublist you get from get_all_factors
        factors = [x for x in factor if x not in get_all_smaller_factors(x)] 
    return factors

#Note: again, I'm too tired to find proper names, please improve later.
def accept(input_var, range):
    factors = min_factor_list(range)
    for factor in factor:
         if(input_var % factor is not 0):
            return false

    return true

Now that you have the boring stuff out of the way, here is a simple oneliner that will do your work:

 print "Is %d divisible by range(1,%d)? %r"%(z,max,accept(z,max))

Disclaimer: I haven't actually tried out the code, but this SHOULD work.

Edit: Another (not completely unrelated but certainly better) approach is to use the range (1..range_max) and find the least common multiple (ie LCM ). From there, you can simply check if the LCM is a factor of Z or not.

The min_factor_list method should help with this. You can simply multiply every element in that list and get the LCM (no elements in the list has another element as its factor or simply put, all the elements are relatively prime)

Why does this work? Because Z must be atleast as big as the LCM . Now what is the next time you get a number that is divisible by all the numbers? That is the same time as LCM*2 . And the next time after that? LCM*3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM