Python algorithm for prime numbers - python

I'm trying to filter off the prime numbers from 1 to 100 and here is the codes. However, it turns out that there are many numbers missed in the output.
def isnot_prime(x):
if x == 1:
return True
if x == 2:
return False
for i in range(2, int(x**0.5)+1):
if x % i == 0:
return True
else:
return False
print filter(isnot_prime, range(1,101))
The output is [1, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100].
There must be something wrong with the algorithm. How can I improve it?
Thank you.

Modify your for to this:
for i in range(2, int(round(x**0.5 + 1))+1):
if x % i == 0:
return True
Remove the else: and remember that int(float) just takes the integral part (it does not round).
Also, keep in mind that there are faster algorithms to do this. For example the Sieve of Eratosthenes is a fast and simple algorithm.

I would do it this way :
print filter(lambda x: len(['' for y in range(2,x) if x%y==0])==0,range(1,101) )

Related

Modification/creation of new lists

I have been tasked with finding the even numbers from this list and multiplying them all together. I have used modulus to find the evens, and have a way of multiplying a list, however I do not know how to place the even values found by the modulus into a new list to be modified.
Here is the list:
list3 = [146, 875, 911, 83, 81, 439, 44, 5, 46, 76, 61, 68, 1, 14, 38, 26, 21]
and here is what I have for finding even:
for num in list3:
if (num % 2 ==0):
print(even_list)
and I am using a multiplication function I created earlier:
def multiply_list(list1):
result = 1
for num in list1:
result = result * num
return result
Forgive me, I am sure this is an easy fix. I am very new to this.
I am not sure if I understood your question properly. Below is the code to insert elements in the list.
list3 = [146, 875, 911, 83, 81, 439, 44, 5, 46, 76, 61, 68, 1, 14, 38, 26, 21]
even_list = []
for num in list3:
if (num % 2 ==0):
even_list.append(num)
print(even_list)
If you want to multiply the even elements in the list, use below code.
def evenList(list):
even_list = []
for num in list:
if (num % 2 ==0):
even_list.append(num)
return even_list
def multiply_list(list1):
result = 1
for num in list1:
result = result * num
return result
list3 = [146, 875, 911, 83, 81, 439, 44, 5, 46, 76, 61, 68, 1, 14, 38, 26, 21]
print(multiply_list(evenList(list3)))
The list of even numbers can be found by using a for loop, or a list comprehension for more concise syntax. Then use functools.reduce to multiply the elements together.
from functools import reduce
list3 = [146, 875, 911, 83, 81, 439, 44, 5, 46, 76, 61, 68, 1, 14, 38, 26, 21]
even_list = [n for n in list3 if n % 2 == 0]
print(even_list) # [146, 44, 46, 76, 68, 14, 38, 26]
even_product = reduce(lambda product, n: n*product, even_list)
print(even_product) # 21123741743104

Something wrong with my quick sort Python code?

I meet a issue with my quick sort code.
class Sort:
def quickSort(self, unsortedlist):
if len(unsortedlist) <= 1:
return unsortedlist
pivot = unsortedlist[0]
unsortedlist.remove(unsortedlist[0])
left, right = [], []
for num in unsortedlist:
if num < pivot:
left.append(num)
else:
right.append(num)
return self.quickSort(left) + [pivot] + self.quickSort(right)
if __name__ == "__main__":
a = [76, 76, 65, 72, 58, 64, 82, 3, 22, 31]
print(Sort().quickSort(a))
print(Sort().quickSort(a))
print(Sort().quickSort(a))
The result will be:
[3, 22, 31, 58, 64, 65, 72, 76, 76, 82]
[3, 22, 31, 58, 64, 65, 72, 76, 82]
[3, 22, 31, 58, 64, 65, 72, 82]
Why the sorted list become less and less?
unsortedlist.remove(unsortedlist[0])
So every time you call quickSort on a list you remove the first element from the source list.
It doesn't really matter for the recursive calls because you "control" the list, but for the "top-level" calls after every call to quickSort you've "lost" one of the elements.

Python Data structure index Start at 1 instead of 0?

I have a weird question: I have this list of 64 numbers that will never change:
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128)
I need a data structure in Python that will allow me to accsess these numbers using a 1-64 index as opposed to the standard 0-63. Is this possible? Would the best way to accomplish this be to build a dictionary?
Just insert a 0 at the beginning of the structure:
(0, 2, 4, 6, 8, ...)
You could override the item getter and make a specialized tuple:
class BaseOneTuple(tuple):
__slots__ = () # Space optimization, see: http://stackoverflow.com/questions/472000/python-slots
def __new__(cls, *items):
return tuple.__new__(cls, items) # Creates new instance of tuple
def __getitem__(self, n):
return tuple.__getitem__(self, n - 1)
b = BaseOneTuple(*range(2, 129, 2))
b[2] == 4
You could use a dictionary, or you could simply subtract one from your index before accessing it.
Also, I note that your 64 numbers are in a simple arithmetic progression. Why store them at all? You can use this:
def my_number(i):
return 2*i
If the list you showed was actually an example, and the real numbers are more complicated, then use a list with a dummy first element:
my_nums = [0, 2, 4, 6, 8, ....]
Then you can get 2 as my_nums[1].
You could use range(2, 129, 2) to generate the numbers in the range 1 - 128 in increments of 2 and convert this list into a tuple if it's not going to change.
t = tuple(range(2, 129, 2))
def numbers(n):
return t[n-1]
Given the global tuple t, function numbers could retrieve elements using a 1-based (instead of 0-based) index.

Errors when modifying a dictionary in python

Suppose I want to create a dictionary that maps digits to numbers less than 100 ending in those digits as follows:
d = {}
for i in range(100):
r = i % 10
if r in d:
d[r] = d[r].append(i)
else:
d[r] = [i]
print d
First of all, when i is 20, d[r] is apparently a NoneType when I try to append to it, throwing an error. Why would this be? Secondly, I feel like my approach is inefficient, as the work in checking if r in d isn't propagated. Something like this would be better, I feel:
case(d[r]) of
SOME(L) => d[r] = L.append(i)
| NONE => d[r] = [i]
Is there a way to have that logic in python?
First of all, when i is 20, d[r] is apparently a NoneType when I try to append to it, throwing an error. Why would this be?
This is because the following code is wrong:
d[r] = d[r].append(i)
.append modifies the list as a side effect, and returns None. So after the list is appended to, it gets thrown away and replaced with the None value now being re-assigned into d[r].
Is there a way to have that logic in python?
There are a variety of hacks that can be used, but none of them are appropriate here.
Instead, solve the specific problem: "modify a dictionary value if present, or create a new value otherwise". This can be refined into "create an empty default value if absent, and then modify the value now guaranteed to be present".
You can do that using .setdefault, or more elegantly, you can replace the dictionary with a collections.defaultdict:
from collections import defaultdict
d = defaultdict(list)
for i in range(100):
r = i % 10
d[r].append(i)
Or you can solve the even more specific problem: "create a dictionary with a given pattern", i.e. from applying a rule or formula to an input sequence (in this case, the input is range(100):
from itertools import groupby
def last_digit(i): return i % 10
d = {k: list(v) for k, v in groupby(sorted(range(100), key=last_digit), last_digit)}
Or you can solve the even more specific problem, by taking advantage of the fact that range takes another argument to specify a step size:
d = {i: range(i, 100, 10) for i in range(10)}
With Andrew's suggestion to use d[r].append(i), you get the desired answer:
In [3]: d
Out[3]:
{0: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90],
1: [1, 11, 21, 31, 41, 51, 61, 71, 81, 91],
2: [2, 12, 22, 32, 42, 52, 62, 72, 82, 92],
3: [3, 13, 23, 33, 43, 53, 63, 73, 83, 93],
4: [4, 14, 24, 34, 44, 54, 64, 74, 84, 94],
5: [5, 15, 25, 35, 45, 55, 65, 75, 85, 95],
6: [6, 16, 26, 36, 46, 56, 66, 76, 86, 96],
7: [7, 17, 27, 37, 47, 57, 67, 77, 87, 97],
8: [8, 18, 28, 38, 48, 58, 68, 78, 88, 98],
9: [9, 19, 29, 39, 49, 59, 69, 79, 89, 99]}
You could do this:
In [7]: for onesdigit in range(10):
...: d[onesdigit] = range(onesdigit, 100, 10)

Python- Sieve of Eratosthenes- Compact Python

This is my code for finding primes using the Sieve of Eratosthenes.
list = [i for i in range(2, int(raw_input("Compute primes up to what number? "))+1)]
for i in list:
for a in list:
if a!=i and a%i == 0:
list.remove(a)
Trying to find a way to compress those nested for loops into some kind of generator or comprehension, but it doesn't seem that you can apply a function to a list using a comprehension. I tried using map and filter, but I can't seem to get it right.
Thinking about something like this:
print map(list.remove(a), filter(lambda a, i: (a%i ==0 and a!=i), [(a, i) for i in list for a in list])
Obviously doesn't work for a dozen reasons. If I just was using the filter portion of that code:
filter(lambda a, i: (a%i ==0 and a!=i), **[(a, i) for i in list for a in list]**
What's the proper way of putting two variables into the lambda? (a,i) makes it a tuple, but I want to submit 'a' and 'i' as independent variables to put into the lambda.
I ended up resolving the problem with this one-liner:
print sorted(set([i for i in range(2, int(raw_input("Compute primes up to what number? "))+1)]).difference(a for i in l for a in l if a!=i and a%i == 0))
The first thing to note is that what you have written is not the sieve of eratosthenes. Look how many loops a totally naive sieve of eratosthenes executes:
def sieve1(n):
loops = 0
numbers = set(range(2, n))
for i in range(2, int(n ** 0.5) + 1):
for j in range(i * 2, n, i):
numbers.discard(j)
loops += 1
return sorted(numbers), loops
Tested:
>>> sieve1(100)
([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],
178)
178 loops for 100 numbers (not including the sort). This can be improved with a few minor changes:
def sieve2(n):
loops = 0
numbers = range(0, n)
for prime in numbers:
if prime < 2:
continue
elif prime > n ** 0.5:
break
for i in range(prime ** 2, n, prime):
numbers[i] = 0
loops += 1
return [x for x in numbers if x > 1], loops
Tested:
>>> sieve2(100)
([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],
102)
102 loops for 100 numbers (not including the filter at the end). Now look at yours:
def sieve3(n):
loops = 0
numbers = range(2, n)
for i in numbers:
for j in numbers:
if j != i and j % i == 0:
numbers.remove(j)
loops += 1
return numbers, loops
Tested:
>>> sieve3(100)
([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],
663)
It gets worse:
>>> [sieve1(x)[1] for x in [100, 1000, 10000]]
[178, 2978, 41723]
>>> [sieve2(x)[1] for x in [100, 1000, 10000]]
[102, 1409, 16979]
>>> [sieve3(x)[1] for x in [100, 1000, 10000]]
[663, 28986, 1523699]
At n = 10000, your implementation does almost 100x as much work!
My suggestion would be to create a sensible implementation before making it "compact." Code golf can be fun, but it's nowhere near as challenging or as edifying as writing efficient code, whatever the length.
That said, consider this one-liner (if you don't count the import, which you could get rid of by using lambda x, y: x - y in place of operator.sub). This implements the first algorithm with a small improvement:
>>> from operator import sub
>>> reduce(sub, (set(range(x ** 2, 100, x)) for x in range(2, int(100 ** 0.5) + 1)), set(range(2, 100)))
set([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])
It's not precisely a direct translation of your loops, but it's quite close and compact:
>>> l = range(2, 101)
>>> sorted(set(l).difference(a for i in l for a in l if a!=i and a%i == 0))
[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]
Although I'd suggest a > i rather than a != 0 as being shorter and faster ;)
You are not doing the Sieve of Eratosthenes; the danger of not properly implementing the algorithm is that it will be extremely slow. Try your algorithm on 10**6 for example.
Shortest implementation of the bounded Sieve of Eratosthenes I can come up with:
def primes(upTo):
isPrime = list(range(upTo))
for p in range(2,int(upTo**0.5)+1): #p: 2,3,4,...,sqrt(N)
print(p, isPrime[p])
if isPrime[p]:
for multiple in range(p**2,upTo,p): #mult: p^2, p^2+p, p^2+2p, ..., N
isPrime[multiple] = False
return [x for x in isPrime[2:] if x]
Demo:
>>> list(primes(29))
[2, 3, 5, 7, 11, 13, 17, 19, 23]
It's actually rather succinct, if you ignore linebreaks and the massive skip-even-numbers optimization:
isPrime=[True]*upTo for p in range(2,upTo): if isPrime[p]: yield p for m in range(p,upTo,p): isPrime[m]=False
Here is the most compact true sieve I have come up with so far. This performs surprisingly well.
def pgen(n): # Sieve of Eratosthenes generator
np = set() # keeps track of composite (not prime) numbers
for q in xrange(2, n+1):
if q not in np:
yield q
np.update(range(q*q, n+1, q))
>>> list(pgen(100))
[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]
This slightly more complex version is the fastest I have seen:
def pgen(n): # Sieve of Eratosthenes generator by Dan Salmonsen
yield 2
np = set()
for q in xrange(3, n+1, 2):
if q not in np:
yield q
np.update(range(q*q, n+1, q+q))
Here is a true sieve as a list comprehension:
def primes(n):
sieve = set(sum([range(q*q, n+1, q+q) for q in odds], []))
return [2] + [p for p in odds if p not in sieve]
>>> primes(100)
[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]
The following one-liner is not related at all to your code:
def primes(n):
return set(range(2,n))-{c for i in range(2,n) for c in range(2*i,n,i)}
Like your code, this is still not really the Sieve of Eratosthenes because, for example, it will futilely try to cross off multiples of 6 and 9 etc. Nevertheless it still runs significantly faster than most other Sieve look-alikes for values less than a million or more, since for small N there are "about as many" primes as non-primes (the fraction of numbers < N that are prime is 1/log(N)).
Heavily modified from source, possibly less efficient than original: http://codeblog.dhananjaynene.com/2011/06/10-python-one-liners-to-impress-your-friends/
Here's a simple demonstration of the sieve. Note that lambda isn't used as the filtering function, because the prime number needs to bound at definition time. Also of interest is that it's efficient in the sense of not duplicating divisions, but in the long run it could lead to you-know-what.
import itertools
def primes():
ints = itertools.count(2)
while True:
p = next(ints)
yield p
ints = itertools.ifilter(p.__rmod__, ints)
print list(itertools.islice(primes(), 10))
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
def sieve(n):
sieve_list = range(n)
zero_list = [0] * n
for i in range(2, int(n**.5) + 1):
if sieve_list[i]:
sieve_list[2*i:n:i] = zero_list[2*i:n:i]
return filter(None, sieve_list)[1:]
Not exactly the the most compact solution, but the step argument in the range function in Python3 helps here -
prime_sieve = [True] * (int(input('Primes Upto ?'))+1)
# The first prime number
for i in range(2, len(prime_sieve)):
if prime_sieve[i]:
for j in range(i+i, len(prime_sieve), i):
prime_sieve[j] = False
print(i, end=',')

Categories

Resources