I am trying to figure out why these two snippets should essentially do the same work, but somehow they do not.
I want to find the prime numbers between 1-100. And I know this could work:
# This create an empty list first.
# if number qualifies the prime number then append, if not then break.
pnumber1 = []
for x in range(2, 101):
for i in range(2, x):
if x % i == 0:
break
else:
pnumber1.append(x)
print(pnumber1)
So I was trying to play in another way, that I create a list of all numbers 1-100, and remove the number that is not prime number. Then what's left should be the prime number list. So I have:
# note: this code should exclude '2', which is a prime number, I'll worry about that later.
pnumber1b = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
pnumber1b.remove(x)
else:
break
print(pnumber1b)
Somehow, this won't work, as it will return every number from 3-100. That means the pumber1b.remove(x) did not work.
OK, if I try it this way:
pnumber1b = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
pnumber1b.remove(x)
else:
break
print(pnumber1b)
to change the indent level, it will still return: list.remove(x): x not in list
of course it will not work : take the example of i=2,x=6 , 6 is not prime ergo you remove it.
on the next iteration of i, i=3 you come across x=6 one again and try to remove it again! so you are getting the error : list.remove(x): x not in list .
and of course the most important note: you cannot change the list that you are iterating over! when you remove item x from list your next iteration will be invalid and the list will be corrupted!
try something like adding another if that asks if x is still in pnumber1b:
pnumber1b = list(range(3, 101))
pnumber1a = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
if x in pnumber1a:
pnumber1a.remove(x)
break
else:
continue
print(pnumber1a)
or simply add break after your remove command since there is no need to continue running on the number x.
pnumber1b = list(range(3, 101))
pnumber1a = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
pnumber1a.remove(x)
break
print(pnumber1a)
There's some unclear behavior that makes your first code work which doesn't happen in the second one.
A for loop executes the else statement if it manages to finish naturally without a break.
This prints "Ok!":
for i in range(10):
if i == 11: break # Condition not reached, loop ends naturally
else:
print('Ok!')
While this doesn't:
for i in range(10):
if i == 5: break
else:
print('Ok!')
If, as you were doing, you do this:
pnumber1b = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
pnumber1b.remove(x)
else:
break
Then it will reach the end of the for i in range(2, x): naturally, will trigger the else and break out of the outer loop, without checking most values.
You could remove the else:
pnumber1b = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
pnumber1b.remove(x)
print(pnumber1b)
This will fail because on numbers with more than one multiple, it will try to remove the item twice and raise an exception when it doesn't find the item it already removed.
You could then add a break to stop looking for multiples after finding the first one:
pnumber1b = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
pnumber1b.remove(x)
break
print(pnumber1b)
And this would work except for the fact that removing list items while iterating over the list causes problems with the iteration. You'll see that it'll start removing only even numbers.
What does work (but is a bit pointless, given the first example you showed) is creating a new list, adding the non-primes to that list, and then, after iterating over the list, removing them:
to_remove = []
pnumber1b = list(range(3, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
to_remove.append(x)
break
for r in to_remove:
pnumber1b.remove(r)
print(pnumber1b)
#ddor254
your first set of codes are not right, it will only remove the even number.
I changed it to:
pnumber1b = list(range(2, 101))
pnumber1a = list(range(2, 101))
for x in pnumber1b:
for i in range(2, x):
if x % i == 0:
if x in pnumber1a:
pnumber1a.remove(x)
else:
continue
print(pnumber1a)
Now this will work
This method requires that you fill in the array with some known prime values. The more primes you add to the list the more accurate the checker will become.
I've ran this against the first 168 prime numbers without it skipping a beat. I do recommend that you grab your own list of prime numbers to test against it and see if anything returns "False" when it should return "True".
def isprime(n):
if n==0 or n==1: return False
testlist = [2,3,5,7,9,11]
grand = 0
for test in testlist:
if n==test: return True
elif n%test==0: return False
else: grand += 1
if grand > 0: return True
else: return False
Using this in your favor can be done in this manner:
primearr = []
for x in xrange(1, 1000000):
if isprime(x) == True:
primearr.append(x)
This code is fast enough for me to run the first 1000000 numbers in about a second or two. Now if you want to view the results then it's best that you throw them into a text document than reading them out (which can freeze or crash Python) like this:
with open('primelist.txt', 'a') as f:
for prime in primearr:
f.write('{},'.format(prime))
Then you can check the directory where you have Python installed to find the text document unless you specified a directory in the filename like this:
with open('C:\\Users\\yourname\\Desktop\\primelist.txt', 'a') as f:
EDIT
I know this is a necro-edit but I feel that it's necessary because I did get it to successfully check the first 10,000,000 prime numbers with the same exact prime test list.
I got the first 10,000,000 primes from this source: http://www.primos.mat.br/2T_en.html
primelist = []
with open('first-ten-million-primes', 'r') as r:
primes = r.readlines()
for prime in primes:
for num in prime.split('\t'):
primelist.append(int(num))
testlist = [2,3,5,7,9,11]
success, failure = [], []
for prime in primelist:
grand = 0
for test in testlist:
if prime % test == 0 and prime != test: grand += 1
if grand > 0: failure.append(prime)
else: success.append(prime)
print('Successes: {}\r\nFailures: {}'.format(len(success), len(failure)))
That output returned:
Successes: 10000000
Failures: 0
This was all on Python 3.6.5 x64.
Related
I have a hackkerank coding challenge to print first n non prime numbers, i have the working code but the problem is that they have a locked code which prints numbers from 1 to n along with the output, in order to pass the test i need to print only the non prime numbers not 1...n numbers along with it. I cant comment the printing part of 1...n as it is blocked. please let me know the idea to print only 1st n non prime numbers:
here is my solution:
def manipulate_generator(generator, n):
if n>1:
ls=[1]
for elm in generator:
if elm>3 and len(ls)<n:
for k in range(2,elm):
if elm%k==0 and elm not in ls:
ls.append(elm)
print(elm)
if len(ls)==n:
return ls
That's the code I added but here is the code that's locked on which I have to write the code above to make it print the number one at a time
def positive_integers_generator():
n = 1
while True:
x = yield n
if x is not None:
n = x
else:
n += 1
k = int(input())
g = positive_integers_generator()
for _ in range(k):
n = next(g)
print(n)
manipulate_generator(g, n)
the point is the for _ in range(k): already prints out number which includes numbers I don't want printed out: This is the desired kind of output I want:for n=10 I want it to print out:
output:
1
4
6
8
9
10
12
14
15
16
I can't change this code but the one above is what I wrote and can be changed... Pleae help me out... Thanks in anticipation
Why not to throw away the numbers which we don't need? Look at this solution which I implemented...
def is_prime(n):
for i in range(2, n):
if n%i == 0:
return False
return True
def manipulate_generator(generator, n):
if is_prime(n+1):
next(generator)
manipulate_generator(generator, n+1)
Note: I understand that the logic can be improved to make it more efficient. But, its the idea of skipping unnecessary number printing which is important here !
You can print all the numbers from 1 up to the first prime number and then from that first number to the next one until you reach n.
I'm not sure of your hackerrank situation, but printing the first N non-prime numbers efficiently can be done this way.
def non_prime_numbers_till_n(n):
primes = set()
for num in range(2,number + 1):
if num > 1:
for i in range(2, math.sqrt(num)):
if (num % i) == 0:
break
else:
primes.add(num)
result = []
for i in range(1, n):
if i not in primes:
result.append(i)
return result
Depending on what your online editor expects you can either print them, or store them in a list and return the list.
Also bear in mind, you can only check upto the sqrt of the number to determine if its a prime or not.
I eventually came up with this answer which I believe should solve it but id there;s a better way to solve it please add your answers:
def manipulate_generator(generator, n):
for num in range(3,100000):
for q in range(2,num):
if num%q==0 and num>n:
generator.send(num-1)
return
this link python generator helped me to understand python generator
I just solved that right now. Like Swapnil Godse said you need to deal with all special cases to optimize computations. This link might be helpful: click here.
Here is the solution:
from math import sqrt
def is_prime(n):
if (n <= 1):
return False
if (n == 2):
return True
if (n % 2 == 0):
return False
i = 3
while i <= sqrt(n):
if n % i == 0:
return False
i = i + 2
return True
def manipulate_generator(g, n):
if is_prime(n+1):
next(g)
manipulate_generator(g, n+1)
prime = int(input('Please enter the range: '))
prime_number = []
for num in range(prime):
if num > 1:
for i in range(2,num):
if num % i == 0:
break
else:
prime_number.append(num)
print(f'Prime numbers in range {prime} is {prime_number}')
all_number = []
for i in range(2,prime+1):
all_number.append(i)
Non_prime_number = []
for element in all_number:
if element not in prime_number:
Non_prime_number.append(element)
print(f'Non Prime numbers in range {prime} is {Non_prime_number}')
Problem
When 32, and select other numbers are inputted, the following error is given:
Traceback (most recent call last):
File "python", line 43, in <module>
IndexError: list assignment index out of range
(Line 43 is extrafactors[i] = factorCheck(i).) However, with other numbers, the code works just fine.
Code
from functools import reduce
n = int(input("Please input a whole number"))
primes = []
def isPrime(x):
if x<2:
return False
for i in range(2,x):
if not x%i:
return False
return True
def factorCheck(n):
x = []
for i in range(1,n):
if n%i==0:
x.append(i)
return x
if isPrime(n) == True:
print("1, ",n)
else:
for i in range (1,n):
if isPrime(i) == True:
if n%i == 0:
primes.append(i)
multiplied = reduce(lambda x, y: x*y, primes)
if multiplied != n:
left = int(n/multiplied)
if isPrime(left) == True:
primes.append(left)
else:
extrafactors = []
extrafactors = factorCheck(left)
while len(extrafactors) > 0:
for i in extrafactors:
if isPrime(i) == True:
primes.append(i)
extrafactors.remove(i)
else:
extrafactors[i] = factorCheck(i)
extrafactors = [item for sublist in extrafactors for item in sublist]
primes = sorted(primes)
print(primes)
Code Explanation
There are two functions defined. One checks if a number is prime, and the other produces a list of factors of a number. First, the program takes in the number inputted by the user. Then, it tests if it is prime, and prints the prime factorization then (1, whatever the number is). If it isn't, it basically finds all primes that are factors of the number and are also prime. The program then multiplies these together, and if they are less than the original number inputted, it finds (prime) factors of the difference and appends them to the list of prime numbers which is printed at the end.
I understand the program may be inefficient, but I understand it how it is written. The line that gives the error replaces a number with a list of factors of that number.
I'm not going to review your code. It's much more complicated than it needs to be.
Here is a simple function for factoring integers. It's not the best way to factor integers, but it's simple and reasonably efficient as long as n isn't too big, less than a dozen digits, say.
def factors(n):
f, fs = 2, []
while f * f <= n:
if n % f == 0:
fs.append(f)
n = n / f
else:
f = f + 1
fs.append(n)
return fs
This problem is easier to do with a recursive function. Recursive functions call themselves. So, basically once we find a factor, we check to see if the number can be factored further, if it can be we append it to the list and keep factoring, if it can't be factored, then we simply append and return.
def factor(numberToFactor, arr=list()):
for i in range(2, numberToFactor // 2 + 1):
if numberToFactor % i == 0:
return factor(numberToFactor/i,arr + [i])
return list(set(arr + [numberToFactor]))
print(factor(32))
I was trying to make a program which would check a number for its greatest prime factor. I was almost done when this error message came up. list index out of range.
What does this mean and what is wrong with my code?
Here is my code.
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
def Problem3():
x = 144
n = 2
not_a_factor = []
z = []
prime = []
not_a_prime = []
while n < x:
if x%n == 0:
z.append(n)
else:
not_a_factor.append(n)
n = n + 1
for i in z:
if is_prime(z[i]) == True:
prime.append(z[i])
else:
not_a_prime.append(z[i])
print(prime)
Problem3()
You're just a bit off. for-loops in Python iterate an object and return it's entities, not a pointer/ index.
So just use the thing you get from each iteration of 'z'
(Side note: might want to check out this post, it'll help you make your is_prime function more performant)
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
def Problem3():
x = 144
n = 2
not_a_factor = []
z = []
prime = []
not_a_prime = []
while n < x:
if x%n == 0:
z.append(n)
else:
not_a_factor.append(n)
n =+ 1 # Python version of n++
for i in z: # Python for-loop is more like a say "for each", no need for the indexing
if is_prime(i): # no need for '=='; Python will 'truthify' your object
prime.append(i)
else:
not_a_prime.append(i)
print(prime)
Problem3()
"list index out of range - what does this mean?"
The message list index out of range refers to an IndexError. Basically, this means that you are attempting to refer to an index in a list that doesn't exist.
Using your code as an example: you generate a list, z, containing the factors of the number 144. You then iterate through each element in this list (for i in z:). This means that for the:
1st iteration: i is the 1st element in z, which is 2;
2nd iteration: i is the 2nd element in z, which is 3;
and so on.
Then, you attempt if isprime(z[i]) == True:. So, as written, your program works like this:
1st iteration: if isprime(z[2]) == True:;
2nd iteration: if isprime(z[3]) == True:;
...
8th iteration: if isprime(z[16]) == True:
At this point, your code prompts an IndexError, because there are only 13 elements in z.
"what is wrong with my code?"
One way to get the result that you want is to iterate through range(len(z)) instead of each element of z. So, adjust the line for i in z to for i in range(len(z)).
Additionally, since prime is a list, and you want to return the greatest prime factor, change print(prime) to print(max(prime)).
These two changes will give you the result you are looking for.
Additional Learnings
Overall, your program could be written much more efficiently. If you want a simple algorithm to determine the greatest prime factor of a number, here is one possibility:
def greatest_prime_factor(n):
greatest_prime = 1
for i in range(n + 1):
# iterate through range(n). We skip index 0.
if i == 0:
continue
# determine if the number i is a factor of n.
if n % i == 0:
# determine if the number i is prime.
for i_ in range(2,i):
if i % i_ == 0:
break
else:
# update greatest_prime.
greatest_prime = max(greatest_prime, i)
return greatest_prime
print (greatest_prime_factor(144))
This algorithm saves a lot of memory space when compared with your original program by not initializing lists to store numbers that are primes, that aren't primes, etc. If you want to store those values, that's up to you; there are just far more efficient possibilities for what you appear to want to achieve.
Check this link for some more info on algorithmic efficiency and how to think about time and space complexity.
How can I turn the result of this code into a list or a set?
def factors(x):
for i in range(1, x + 1):
if x % i == 0:
print(i)
num = 100
factors(num)
You need to return something rather than print. You can build a list in the function:
def factors(x):
result = []
for i in range(1, x + 1):
if x % i == 0:
result.append(i)
return result
num = 100
print(factors(num))
You can make that a set too, if you want, using result = set() and result.add().
The other option is to turn the function into a generator; you'd have to do some iteration after calling the function:
def factors(x):
for i in range(1, x + 1):
if x % i == 0:
yield i
num = 100
for factor in factors(num):
print(factor)
but you can also 'pull in' all the values into a list or set:
factors_list = list(factors(num))
factors_set = set(factors(num))
Check the divisibility till the square root of the value. If matches, add divisor and quotient to the factors list. Then create a set out of the list to remove repeated elements (which will only arise if x is a square of an integer). Finally return the list after sorting it so that the returned list is in ascending order.
import math
def factors(x):
f = []
for i in range(1, math.ceil(math.sqrt(x))+1):
if x % i == 0:
f.append(i)
f.append(x/i)
return sorted(set(f))
I'm working on problem #3 on project euler, and I've run into a problem. It seems that the program is copying all the items from factors into prime_factors, instead of just the prime numbers. I assume this is because my is_prime function is not working properly. How can I make the function do what I want? Also, in the code, there is a line that I commented out. Do I need that line, or is it unnecessary? Finally, is the code as a whole sound (other than is_prime), or is it faulty?
The project euler question is: The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143 ?
A link to a previous question of mine on the same topic: https://stackoverflow.com/questions/24462105/project-euler-3-python?noredirect=1#comment37857323_24462105
thanks
import math
factors = []
prime_factors = []
def is_prime (x):
counter = 0
if x == 1:
return False
elif x == 2:
return True
for item in range (2, int(x)):
if int(x) % item == 0:
return False
else:
return True
number = int(input("Enter a number: "))
start = int(math.sqrt(number))
for item in range(2, start + 1):
if number % item == 0:
factors.append(item)
#factors.append(number/item) do i need this line?
for item in factors:
if is_prime(item) == True:
prime_factors.append(item)
print(prime_factors)
Yes, you need the commented line.
(It seems that on that case it's not necessary, but with other numbers the part of your code for getting factors would go wrong).
Check these references:
Prime numbers
Integer factorization
Why do we check up to the square root of a prime number to determine if it is prime or not
I got a very fast result on my computer with the following code:
#!/usr/bin/env python
import math
def square_root_as_int(x):
return int(math.sqrt(x))
def is_prime(number):
if number == 1:
return False
for x in range(2, square_root_as_int(number) + 1):
if x == number:
next
if number % x == 0:
return False
return True
def factors_of_(number):
factors = []
for x in range(2, square_root_as_int(number) + 1):
if number % x == 0:
factors.append(x)
factors.append(number/x)
return factors
factors = factors_of_(600851475143)
primes = []
for factor in factors:
if is_prime(factor):
primes.append(factor)
print max(primes)
# Bonus: "functional way"
print max(filter(lambda x: is_prime(x), factors_of_(600851475143)))
Your is_prime() returns early. Here's a fixed version:
def is_prime (x):
if x == 1:
return False
if x == 2:
return True
for item in range (2, int(x)):
if int(x) % item == 0:
return False
return True
you should not be using int(x) in the way that you currently are. i know you're forcing the int type because you want to convert from string input, but this will also allow the user to enter a float (decimal), and have it interpreted as either prime or not. that is bad behavior for the function. see my solution below. if you use eval to verify the input, you can just use x later, in place of int(x).
import math
factors = []
prime_factors = []
def is_prime (x):
x = eval(x) # this will cause a string like '5' to be evaluated as an integer.
# '5.2' will be evaluated as a float, on the other hand.
if type(x) != int:
raise Exception('Please enter an integer.') #prevents bad input
counter = 0 #this counter is not used. why is it initialized here?
if x == 1:
return False
elif x == 2:
return True
for item in range (2, x):
if x % item == 0:
return False
else:
return True
Use the while loop. n%i simply means n%i!=0
i = 2
n = 600851475143
while i*i <= n:
if n%i:
i+=1
else:
n //= i
print n