How does this if all statement work? Euler 7 - python

I was looking at the code below and I can't seem to get my head around line 6 with the if all statement.
Could someone explain what it is doing and what happens in the first iteration when the list is empty. This is from Euler 7
def main():
number_prime_to_find = 1001
x = 2
list_of_primes = []
while (len(list_of_primes) < number_prime_to_find):
if all(x % prime for prime in list_of_primes):
list_of_primes.append(x)

The block:
if all(x % prime for prime in list_of_primes):
list_of_primes.append(x)
means "check that, for all primes in the list, x is not a multiple of that prime". It's effectively the same as (pseudo-code):
xIsAPrime = True
for each prime in list_of_primes:
if x % prime == 0:
xIsAPrime = False
break
if xIsAPrime:
list_of_primes.append(x)
If a candidate prime is not a multiple of any primes in the list, then that candidate prime is an actual prime, so is added to the list.
If the list of primes is empty (initial state), then the first number you check will be considered a prime (you're starting at 2 so that's correct).
The reason for this is that all(x) simply means "true if there are no falsey values in the iterable x, false otherwise". Since an empty iterable cannot have falsey values by definition, performing all() on it will always give true.
Following that (the addition of 2 to the list):
The next prime will then be the next number that's not a multiple of two, so we add 3;
The next prime after that will be the next number that's not a multiple of two or three, so we add 5;
The next prime after that will be the next number that's not a multiple of any in the set { 2, 3, 5 }, hence we add 7;
The next prime after that will be the next number that's not a multiple of any in the set { 2, 3, 5, 7 }, add 11;
And so on, until the list size gets big enought that the final item is the prime we want.
Unfortunately for you, that bit of code doesn't seem to ever change x (unless you've just left it off in the question) so it's unlikely to give you what you want, especially since you also don't seem to print or return it. You can rectify that with:
def main():
number_prime_to_find = 1001
list_of_primes = []
x = 2
while len(list_of_primes) < number_prime_to_find:
if all(x % prime for prime in list_of_primes):
list_of_primes.append(x)
x += 1 # Need to modify x
return list_of_primes[-1] # Probably also want to output it.
print(main())
As an aside, you could further optimise this by realising that, other then two and three, all primes are of the form 6n ± 1, for n > 0 (see here for a more detailed explanation as to why this is the case):
def main():
number_prime_to_find = 1001
list_of_primes = [2, 3]
(x, xadd) = (5, 2)
while len(list_of_primes) < number_prime_to_find:
if all(x % prime for prime in list_of_primes):
list_of_primes.append(x)
x += xadd # Skip impossible primes.
xadd = 6 - xadd # Alternate adding 2, 4: gives 7, 11, 13, 17, ...
return list_of_primes[-1]
print(main())
This is likely to be about (very roughly) three times faster, since you only need to check two candidates in each group of six numbers, rather than the original six candidates.
You may also want to consider making it a more generic function. While finding the 1001st prime is something we all want to do three or four times a day, you may want to avoid having to write a whole other function should some new starter on the team decide they want to get the 1002nd :-)
Something like this, I would imagine:
def getNthPrime(n):
# Cater for smart-alecs :-)
if n < 1: return None
# Initial list holds those that aren't 6n +/- 1.
primeList = [2, 3]
# Next candidate and candidate increment.
(candidate, delta) = (5, 2)
# Until we have enough primes in list.
while len(primeList) < n:
# Add to list if it's prime, move to next candidate.
if all(candidate % prime for prime in primeList):
primeList.append(candidate)
candidate += delta
delta = 6 - delta
# List big enough, return correct one. Note we use n-1 here
# rather than -1, since you may want prime #1 and the list
# STARTS with two primes. We subtract one because first prime
# is actually at index zero.
return primeList[n-1]
print(getNthPrime(1001))

Related

How can I print out all the results?

Here the problem is to get all 4 pairs factors of pretty big number 17309205.
Results should be
{1,1,1,17309205}
{1,1,3,5769735} etc..
I tried with 4 nested for loops but it took too long, so I tried a different idea.
My way of thinking is to find every possible pairs of factors and then filter it out for those containing 4 pairs. But now I only get one result.
And also the results isn't printed in t​he way it should be.
def s(target, numbers,memo={}):
if target == 0:
return 0
if target == 1:
return 1
if target < 0:
pass
if target in memo:
return memo[target]
result = []
for n in numbers:
if target%n !=0:
pass
else:
dominator = target/n
result = s(dominator, numbers, memo)
memo[target] = [result,[n,dominator]]
return memo[target]
v = list(range(2,17309205))
print(s(17309205,v))
I see a possible solution. First you have to calculate all the prime factors of the number.
For that you need to create a function which yields prime numbers sequentially.
The function should store the primes in a list and test if the next non tested number is divisible by any prime in the list. If the number is not divisible by any prime in the list, then the number is prime.
For example when you have the list of primes [2,3,5,7] test divisibility of 8 by 2,3,5 and 7. It is divisible by 2 so it is not prime, then go with 9, etc... When reach 11 it is prime so put it in the list and yield 11.
Once calculated all the factor primes of the number you gave, you have to assign each factor to one of 4 places in a list. Then "put" all factors in its corrsponding place by multiplying the number in the place by the factor. You start with [1,1,1,1].
To get all 4 pair factors you need all possible assignments of factors. That is the set product of [0,1,2,3] with itself N times, where N is the number of factors.
(how many pairs are there for N factors?)
For example if there are 5 factors, then an element of the set product is [1, 0, 2, 3, 3] which assign first factor to place 1, second factor to place 0, third factor to place 2 and fourth a fifth factor to place 3.
For the set product we use itertools.product:
import itertools
assignments = itertools.product([0,1,2,3], repeat = len(factors))
for a in assignments:
pair = [1,1,1,1]
for i, place in enumerate(a):
pair[place] *= factor[i]
pairs.append(pair)
I can get desire results with below code but the problems is being too slow if target is too big.
target = 16
for a in range(1,target+1):
for b in range(1,target+1):
for c in range(1, target+1):
for d in range(1, target+1):
if a<=b<=c<=d and a*b*c*d == target:
print (a,b,c,d)

Find nearest prime number python

I want to find the largest prime number within range(old_number + 1 , 2*old_number)
This is my code so far:
def get_nearest_prime(self, old_number):
for num in range(old_number + 1, 2 * old_number) :
for i in range(2,num):
if num % i == 0:
break
return num
when I call the get_nearest_prime(13)
the correct output should be 23, while my result was 25.
Anyone can help me to solve this problem? Help will be appreciated!
There are lots of changes you could make, but which ones you should make depend on what you want to accomplish. The biggest problem with your code as it stands is that you're successfully identifying primes with the break and then not doing anything with that information. Here's a minimal change that does roughly the same thing.
def get_nearest_prime(old_number):
largest_prime = 0
for num in range(old_number + 1, 2 * old_number) :
for i in range(2,num):
if num % i == 0:
break
else:
largest_prime = num
return largest_prime
We're using the largest_prime local variable to keep track of all the primes you find (since you iterate through them in increasing order). The else clause is triggered any time you exit the inner for loop "normally" (i.e., without hitting the break clause). In other words, any time you've found a prime.
Here's a slightly faster solution.
import numpy as np
def seive(n):
mask = np.ones(n+1)
mask[:2] = 0
for i in range(2, int(n**.5)+1):
if not mask[i]:
continue
mask[i*i::i] = 0
return np.argwhere(mask)
def get_nearest_prime(old_number):
try:
n = np.max(seive(2*old_number-1))
if n < old_number+1:
return None
return n
except ValueError:
return None
It does roughly the same thing, but it uses an algorithm called the "Sieve of Eratosthenes" to speed up the finding of primes (as opposed to the "trial division" you're using). It isn't the fastest Sieve in the world, but it's reasonably understandable without too many tweaks.
In either case, if you're calling this a bunch of times you'll probably want to keep track of all the primes you've found since computing them is expensive. Caching is easy and flexible in Python, and there are dozens of ways to make that happen if you do need the speed boost.
Note that I'm not positive the range you've specified always contains a prime. It very well might, and if it does you can get away with a lot shorter code. Something like the following.
def get_nearest_prime(old_number):
return np.max(seive(2*old_number-1))
I don't completely agree with the name you've chosen since the largest prime in that interval is usually not the closest prime to old_number, but I think this is what you're looking for anyway.
You can use a sublist to check if the number is prime, if all(i % n for n in range(2, i)) means that number is prime due to the fact that all values returned from modulo were True, not 0. From there you can append those values to a list called primes and then take the max of that list.
List comprehension:
num = 13
l = [*range(num, (2*num)+1)]
print(max([i for i in l if all([i % n for n in range(2,i)])]))
Expanded:
num = 13
l = [*range(num, (2*num)+1)]
primes = []
for i in l:
if all([i % n for n in range(2, i)]):
primes.append(i)
print(max(primes))
23
Search for the nearest prime number from above using the seive function
def get_nearest_prime(old_number):
return old_number+min(seive(2*old_number-1)-old_number, key=lambda a:a<0)

What is the logic of this code and how does it work so fast?

New to Python and was trying to solve a challenge to find prime factors for large numbers. I soon ran into a roadblock with the logic I was going for. Broadly speaking, my logic was:
Find the factors for a given number and store them in a list
From that list, evaluate each number to check if prime, and if prime
store in a new list
So after #2 I would have a list of primes that were factors of the original number. Got stuck after I realized, I would have to determine the combination of elements in this second list that would make up the original number because all the elements although prime, couldn't necessarily be multiplied with each other to get the original number.
Anyway, after struggling for quite a bit I found the following code that helped with the function I was trying to create.
def prime_factors(n):
# Returns all the prime factors of a positive integer
factors = []
d = 2
while n > 1:
while n % d == 0: #if no remainder
factors.append(d)
n /= d
d = d + 1
if d*d > n:
if n > 1: factors.append(n)
break
return factors
pfs = prime_factors(600851475143)
print(pfs)
total = sum(pfs)
and gives output
[71, 839, 1471, 6857]
Needed some help understanding how this works and also how this is so fast with a 9 digit number. My previous attempts with some logic that either didn't work or would have my command prompt in hang state trying to calculate for the prime factors this big.
Your code is fast because it is using a primality test, an interesting topic.
Keep reading for another solution much simpler for newcomers,
This function will check whether the given integer n is prime or not, when we divide n by i (which is initialized to 2), if the result is 0, the result will be False, because a prime number can only be divided by 1 or itself, if not, i will be incremented (increased) by 1, if i is finally equal to n, the result will be True, because the result of the division of n by i doesn't equal to 0.
def prime(n):
for i in range(2,n): # letting i have multiple values starting from 2
if n % i == 0: # checking the remainder, if it's 0, then n is not prime,
return False # and so False will be returned,
else:
i += 1 # if n is still considered prime, i will become 3, then 4, and so on
# until it becomes equal to n
return True # if so, then n is prime, so True will be returned
Here we will have an empty list called factors in which we will store the prime factors, now take a look at the 4th line, you will see notice that: if n % i == 0 and i is prime, we will add it to our list called factors, we will do that only and only if the two expressions below are True, if the division of n by i doesn't equal to 0 OR/AND i is not prime (meaning prime(i) returned False), we will not then add i to our list, note that i in this function prime_factors is an integer which will be verified to be a factor of n and be prime too.
def prime_factors(n):
factors = [] #initializing an empty list that will soon be modified
for i in range(2,n):
if (n % i == 0) and (prime(i)): # if i is a factor of n and also i is prime
factors.append(i) # the values will be added to our list named factors
return factors # this list contains the prime factors values which, we return it
Giving n a value and then showing the prime factors
n = 81210459 # the value of n
pfs = prime_factors(n) # storing our list returned from this function is the variable pfs
print("prime factors of",n,"are:",pfs) # showing the results (this is obvious isn't it :D)
Output:
Prime factors of 81210459 are: [3, 11, 61, 40343]

Finding numbers from a to b not divisible by x to y

This is a problem I've been pondering for quite some time.
What is the fastest way to find all numbers from a to b that are not divisible by any number from x to y?
Consider this:
I want to find all the numbers from 1 to 10 that are not divisible by 2 to 5.
This process will become extremely slow if I where to use a linear approach;
Like this:
result = []
a = 1
b = 10
x = 2
y = 5
for i in range(a,b):
t = False
for j in range(x,y):
if i%j==0:
t = True
break
if t is False:
result.append(i)
return result
Does anybody know of any other methods of doing this with less computation time than a linear solution?
If not, can anyone see how this might be done faster, as I am blank at this point...
Sincerely,
John
[EDIT]
The range of the number are 0 to >1,e+100
This is true for a, b, x and y
You only need to check prime values in the range of the possible divisors - for example, if a value is not divisible by 2, it won't be divisible by any multiple of 2 either; likewise for every other prime and prime multiple. Thus in your example you can check 2, 3, 5 - you don't need to check 4, because anything divisible by 4 must be divisible by 2. Hence, a faster approach would be to compute primes in whatever range you are interested in, and then simply calculate which values they divide.
Another speedup is to add each value in the range you are interested in to a set: when you find that it is divisible by a number in your range, remove it from the set. You then should only be testing numbers that remain in the set - this will stop you testing numbers multiple times.
If we combine these two approaches, we see that we can create a set of all values (so in the example, a set with all values 1 to 10), and simply remove the multiples of each prime in your second range from that set.
Edit: As Patashu pointed out, this won't quite work if the prime that divides a given value is not in the set. To fix this, we can apply a similar algorithm to the above: create a set with values [a, b], for each value in the set, remove all of its multiples. So for the example given below in the comments (with [3, 6]) we'd start with 3 and remove it's multiples in the set - so 6. Hence the remaining values we need to test would be [3, 4, 5] which is what we want in this case.
Edit2: Here's a really hacked up, crappy implementation that hasn't been optimized and has horrible variable names:
def find_non_factors():
a = 1
b = 1000000
x = 200
y = 1000
z = [True for p in range(x, y+1)]
for k, i in enumerate(z):
if i:
k += x
n = 2
while n * k < y + 1:
z[(n*k) - x] = False
n += 1
k = {p for p in range(a, b+1)}
for p, v in enumerate(z):
if v:
t = p + x
n = 1
while n * t < (b + 1):
if (n * t) in k:
k.remove(n * t)
n += 1
return k
Try your original implementation with those numbers. It takes > 1 minute on my computer. This implementation takes under 2 seconds.
Ultimate optimization caveat: Do not pre-maturely optimize. Any time you attempt to optimize code, profile it to ensure it needs optimization, and profile the optimization on the same kind of data you intend it to be optimized for to confirm it is a speedup. Almost all code does not need optimization, just to give the correct answer.
If you are optimizing for small x-y and large a-b:
Create an array with length that is the lowest common multiple out of all the x, x+1, x+2... y. For example, for 2, 3, 4, 5 it would be 60, not 120.
Now populate this array with booleans - false initially for every cell, then for each number in x-y, populate all entries in the array that are multiples of that number with true.
Now for each number in a-b, index into the array modulo arraylength and if it is true, skip else if it is false, return.
You can do this a little quicker by removing from you x to y factors numbers whos prime factor expansions are strict supersets of other numbers' prime factor expansions. By which I mean - if you have 2, 3, 4, 5, 4 is 2*2 a strict superset of 2 so you can remove it and now our array length is only 30. For something like 3, 4, 5, 6 however, 4 is 2*2 and 6 is 3*2 - 6 is a superset of 3 so we remove it, but 4 is not a superset of everything so we keep it in. LCM is 3*2*2*5 = 60. Doing this kind of thing would give some speed up on its own for large a-b, and you might not need to go the array direction if that's all you need.
Also, keep in mind that if you aren't going to use the entire result of the function every single time - like, maybe sometimes you're only interested in the lowest value - write it as a generator rather than as a function. That way you can call it until you have enough numbers and then stop, saving time.

For loop repeating/stuck? Python 3.2

I am trying to write a python script for Sieve of Eratosthenes. I have everything done, but when I tell the program to test each number if it is a multiple of at least one of the prime numbers below the √input. It goes well but when I try to remove a multiple it works until it tries to delete 6 twice... I've been looking over my code and can't seem to find out why. I'm rather new to Python so help would be much appreciated!
--- Note my code's spacing is off due to SOF's way of making code blocks:
import math, os, threading
global iswhole
global tdprime
def iswhole(x):
if x%1 == 0:
return True
else:
return False
def tdprime(x):
prime = True
n = 2
while n < x:
if iswhole(x/n) == True:
return False
prime = False
n = x
else:
n += 1
if prime == True:
return True
number = 0
while number != 1:
number = int(input("Enter number to calculate all primes up to: "))
number_range = range(1,number+1)
sqrt = math.sqrt(number)
rsqrt = round(sqrt)
thelist = []
tsl = []
for num in range(1,rsqrt):
if tdprime(num) == True:
tsl.append(num)
tsl.remove(1)
for x in number_range: ## Making the List
thelist.append(x)
## Note it's " Key: Value " in dictionaries
print(tsl)
print("thelist: ",thelist)
print("Square root of input = ",sqrt)
print("Rounded Square root of input = ",rsqrt)
print()
for x in thelist: ## Testing each number in thelist
multiple = False
for y in tsl: ## Each prime number under √number
if iswhole(x/y):
print(x) ## If the current number in thelist divided by one of the prime numbers under √number is a whole
thelist.remove(x)## Remove the current number which isn't a prime
thelist.sort()
multiple = True ## Make multiple true so it doesn't print (could remove the multiple stuff and other if function, kind of pointless function now)
if multiple == False:
print("Prime! ",x)
print(thelist)
Your code can be much simplified by the following realisations:
The numbers up to a number n can easily be generated as needed, they don't have to be calculated berforehand and stored in a list.
2 is the only even prime, so you only need to test odd numbers.
All numbers can be fully factorised into prime factors, uniquely (this is called the fundamental theorem of arithmetic). This means that the only numbers which you need to try dividing by are the primes you have previously calculated --- all other numbers will be divisible by at least one of those primes anyway (or they would be primes themselves).
Try something along these lines:
stop = int(input("Enter number to calculate all primes up to: "))
primes = []
for n in range(3, stop, 2): # Step by two each time
was_prime = True # Needed to break out of nested loop
for p in primes:
if n % p == 0: # A prime divides n
was_prime = False
break # No need to continue
if was_prime:
primes.append(n)
print(primes) # You can insert the number 2 here if you like
Also, please pay attention to spacing and indentation. In Python, when you get your spacing wrong it is not only difficult to read, but a runtime error.
I'm a little worried about your iswhole() function:
def iswhole(x):
if x%1 == 0:
return True
else:
return False
(Incidentally, this could be re-written as simply return (x%1 == 0) and skip the return True and return False pieces.)
Floating point numbers are odd creatures:
>>> 10.0%1
0.0
>>> (10.1 * 10)%1
0.0
>>> (10.01 * 100)%1
0.0
>>> (10.001 * 1000)%1
0.0
>>> (10.0001 * 10000)%1
0.0
>>> (10.00001 * 100000)%1
0.0
>>> (10.000001 * 1000000)%1
0.0
>>> (10.0000001 * 10000000)%1
0.0
>>> (10.00000001 * 100000000)%1
1.1920928955078125e-07
For an input such as 6, this doesn't seem likely to be the problem, but it might become a problem for larger inputs. Comparing floating point numbers is troublesome.
For the 6 problem, I'd like to suggest that instead of a mutable list to keep track of your data, you might wish to use an array instead. The array never needs to be sorted (the fact that you have a sort() in your program smells a bit like trying to paper over some kind of bug) and deleting elements from the middles of lists is often extremely expensive. (That sort pretty much means your performance is going to be poor anyhow. Not a big deal for small inputs, but try 1000000 as a starting point.) Setting elements in an array to 1 or 0 is almost always far cheaper than mutable lists.
I see a problem with this bit:
for x in thelist: ## Testing each number in thelist
multiple = False
for y in tsl: ## Each prime number under √number
if iswhole(x/y):
print(x) ## If the current number in thelist divided by one of the prime numbers under √number is a whole
thelist.remove(x)## Remove the current number which isn't a prime
thelist.sort()
You call thelist.remove(x) and thelist.sort() while iterating over thelist. You generally don't want to modify a structure you're iterating over in Python. It usually confuses the internal machinery doing the iteration; you get symptoms like mysteriously skipping elements or processing them twice, or other weirdness.

Categories

Resources