Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have a numpy array like,
nums = np.array([17, 18, 19, 20, 21, 22, 23])
How do I filter out the prime numbers from this array in a pythonic manner?
I know to do a simple filtering like,
nums[nums > 20] #array([21, 22, 23])
Is there a way to pass a lambda function for filtering?
Expected output: array([17, 19, 23])
The way that I would do it is with gmpy or a 3rd party library who has developed a good primality test algorithm. The Miller-Rabin primality test is generally a very safe (and fast!) bet. If you just want the slow way, you can do:
import numpy as np
import math
def is_prime(n):
if n % 2 == 0 and n > 2:
return False
return all(n % i for i in range(3, int(math.sqrt(n)) + 1, 2))
a = np.arange(1, 10**3)
foo = np.vectorize(is_prime)
pbools = foo(a)
primes = np.extract(pbools, a)
primes # => Output below
array([ 1, 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])
If you want to filter OUT the primes, just call np.invert on the pbools variables. The same would go for any predicate. You can also pass a lambda into vectorize. For example, say we wanted only prime numbers that are also 1 away from being divisible by 5 (for whatever reason).
import numpy as np
import math
def is_prime(n):
if n % 2 == 0 and n > 2:
return False
return all(n % i for i in range(3, int(math.sqrt(n)) + 1, 2))
a = np.arange(1, 10**3)
foo = np.vectorize(lambda x: (not (x + 1) % 5 or not (x - 1) % 5) and is_prime(x))
primes = a[foo(a)] # => Shorthand.... Output below
array([ 1, 11, 19, 29, 31, 41, 59, 61, 71, 79, 89, 101, 109,
131, 139, 149, 151, 179, 181, 191, 199, 211, 229, 239, 241, 251,
269, 271, 281, 311, 331, 349, 359, 379, 389, 401, 409, 419, 421,
431, 439, 449, 461, 479, 491, 499, 509, 521, 541, 569, 571, 599,
601, 619, 631, 641, 659, 661, 691, 701, 709, 719, 739, 751, 761,
769, 809, 811, 821, 829, 839, 859, 881, 911, 919, 929, 941, 971, 991])
If you care of speed and efficiency I would recommend you to use one of the fastest prime sieves and numpy.intersect1d() function:
import numpy as np
def primesfrom2to(n):
# http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns a array of primes, 2 <= p < n """
sieve = np.ones(n//3 + (n%6==2), dtype=np.bool)
sieve[0] = False
for i in range(int(n**0.5)//3+1):
if sieve[i]:
k=3*i+1|1
sieve[ ((k*k)//3) ::2*k] = False
sieve[(k*k+4*k-2*k*(i&1))//3::2*k] = False
return np.r_[2,3,((3*np.nonzero(sieve)[0]+1)|1)]
# generate 100.000 random integers from 1 to 1.000.000.000
a1 = np.random.randint(1, 10**9, 100000)
# generate all primes that are equal or less than a1.max()
primes = primesfrom2to(a1.max())
# print result
print(np.intersect1d(primes, a1))
It appears that you question is not about primes at all, but about how to apply a function to numpy array. I used simple is_odd example. Maybe np.vectorize is what you are looking for:
In [34]: nums = np.array([17, 18, 19, 20, 21, 22, 23])
In [35]: def is_odd(n):
if n % 2 == 1:
return True
return False
....:
In [36]: is_odd_v = np.vectorize(is_odd)
In [37]: nums[is_odd_v(nums)]
Out[37]: array([17, 19, 21, 23]
If I recall correctly np.vectorize is used primarily for convenience, and does not have great performance.
Having a setup like this:
import numpy as np
import math
nums = np.array([17, 18, 19, 20, 21, 22, 23])
So now we create an array that contains all possible integer candidates:
divisors = np.arange(2,int(math.sqrt(np.max(nums)))+1) # Numbers from 2 to sqrt(max(nums))
print(divisors)
# [2 3 4]
Now apply the modulo operation on the array but with a different dimension so we check each number with each divisor:
print(nums[:,None] % divisors[None,:]) # Modulo operation on each element (0 means divisible)
[[1 2 1]
[0 0 2]
[1 1 3]
[0 2 0]
[1 0 1]
[0 1 2]
[1 2 3]]
Now how do we get the primes ... we check if there is no result in the line that is zero:
print(np.min(nums[:,None] % divisors[None,:], axis=1)) # Minimum of the modulo for that element
# [1 0 1 0 0 0 1]
and then create a mask to index them:
print(nums[np.min(nums[:,None] % divisors[None,:], axis=1) > 0]) # So index them
# [17 19 23]
So all you need in the end is:
nums = np.array([17, 18, 19, 20, 21, 22, 23])
divisors = np.arange(2,int(math.sqrt(np.max(nums)))+1)
nums[np.min(nums[:,None] % divisors[None,:], axis=1) > 0]
all the other stuff is just for illustrating what each step is doing.
This is not trivial since it uses broadcasting of 1D arrays into a 2D array but the method should be clear. Let me know if you have any questions.
If you want to optimize this, there is another possibility: The divisors are currently every number between 2 and the sqrt(max(array)) but you don't need to test for all these numbers. If you had a function that returned all primes in that range that would be enough. For example using primesfrom2to of #MaxU's answer a faster possibility is:
nums = np.array([17, 18, 19, 20, 21, 22, 23])
# All prime numbers in the range from 2 to sqrt(max(nums))
divisors = primesfrom2to(int(math.sqrt(np.max(nums)))+1)
nums[np.min(nums[:,None] % divisors[None,:], axis=1) > 0]
but it uses the same mechanism as before but is a bit faster. :-)
If you really want to use a Filter, you can use this:
nums[[i for i in range(len(nums)) if sum([nums[i]%val==0 for val in range(2,nums[i]-1)])==0]]
What does this do?
We search all indexes with prime number by using
[i for i in range(len(nums)) if sum([nums[i]%val==0 for val in range(2,nums[i]-1)])==0]
This basically goes through every value and checks if it is not divisible by any value smaller than itself (ignoring 1)
[i for i in range(len(nums)) #for every index
if sum(#calculate sum of booleans
[nums[i]%val==0 for val in range(2,nums[i]-1)] # check if it is divisble by any value smaller than itself
)==0 #check if the number of divisors is zero
Related
This question already has answers here:
Using List comprehensions to solve Collatz conjecture
(4 answers)
Closed 8 months ago.
I have the following code which generates a hailstone sequence of numbers given a user specified positive integer.
n = int(input("Enter a number: "))
seq = [n]
while n > 1:
n = 3 * n + 1 if n % 2 else n // 2
seq.append(n)
print(len(seq))
print(seq)
When given the number 15 it produces the following:
Enter a number: 15
18
[15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]
When given 27 it produces the following:
Enter a number: 27
112
[27, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364,
182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790,
395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566,
283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 2429,
7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 1154, 577,
1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 70, 35, 106,
53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]
Is there a way to use list comprehension to generate such lists rather than using a while loop?
I realize the python standard does not support using a while loop in list comprehension.
No, It is not possible to use while loop inside list comprehension, however you can use something like this.
def hailstorm(n):
while n > 1:
n = 3 * n + 1 if n % 2 else n // 2
yield n
n = int(input("Enter a number: "))
seq = [i for i in hailstorm(n)]
seq.insert(0, n)
print(len(seq))
print(seq)
I want to take the last number and multiply with the multiplier and add the increment. And put that number back into the list. I do not know how to put s into the list. As you can see it is "...8, 4, 2, 1], 4)" I want to put the 4 into the list.
def sfcollatz(n,divs=[2],mult=3,inc=1,maxSize=-1):
result = []
while n not in result and len(result)!=maxSize:
result.append(n)
d = next((d for d in divs if n%d==0),None)
n = (n*mult+inc) if not d else n//d
s = mult*result[-1]+inc
return result + ['...']*(n not in result),s
print(sfcollatz(27,[2],3,1,maxSize=200))
([27, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364, 182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790, 395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566, 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1], 4)
I'm not exactly sure what you mean by "adding 4 into your array". Do you just mean you want it to go "...8, 4, 2, 1, 4]"? If so, you can just use the .append() function again. You also do not need to keep defining s in your while loop since it will always just take the final value:
def sfcollatz(n,divs,mult,inc,maxSize):
result = []
while n not in result and len(result)!=maxSize:
result.append(n)
d = next((d for d in divs if n%d==0),None)
n = (n*mult+inc) if not d else n//d
s = mult*result[-1]+inc
result.append(s)
return result
Your question was a little vague, but I hope this answers it. Let me know if you need any further help or clarification :)
Can Anyone help me with this.I'm getting runtime error for this in online editor as well as in uploading the file but works with correct output in VS Code.
Problem Description
Given two numbers n1 and n2
Find prime numbers between n1 and n2, then
Make all possible unique combinations of numbers from the prime numbers list you found in step 1.
From this new list, again find all prime numbers.
Find smallest (a) and largest (b) number from the 2nd generated list, also count of this list.
Consider smallest and largest number as the 1st and 2nd number to generate Fibonacci series respectively till the count (number of primes in the 2nd list).
Print the last number of a Fibonacci series as an output
Constraints
2 <= n1, n2 <= 100
n2 - n1 >= 35
Input Format
One line containing two space separated integers n1 and n2.
Output
Last number of a generated Fibonacci series.
Timeout
1
Test Case
Example 1
Input
2 40
Output
13158006689
Explanation
1st prime list = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
Combination of all the primes = [23, 25, 27, 211, 213, 217, 219, 223, 229, 231, 32, 35, 37, 311, 313, 319, 323, 329, 331, 337, 52, 53, 57, 511, 513, 517, 519, 523, 529, 531, 537, 72, 73, 75, 711, 713, 717, 719, 723, 729, 731, 737, 112, 113, 115, 117, 1113, 1117, 1119, 1123, 1129, 1131, 1137, 132, 133, 135, 137, 1311, 1317, 1319, 1323, 1329, 1331, 1337, 172, 173, 175, 177, 1711, 1713, 1719, 1723, 1729, 1731, 1737, 192, 193, 195, 197, 1911, 1913, 1917, 1923, 1929, 1931, 1937, 232, 233, 235, 237, 2311, 2313, 2317, 2319, 2329, 2331, 2337, 292, 293, 295, 297, 2911, 2913, 2917, 2919, 2923, 2931, 2937, 312, 315, 317, 3111, 3113, 3117, 3119, 3123, 3129, 3137, 372, 373, 375, 377, 3711, 3713, 3717, 3719, 3723, 3729, 3731]
2nd prime list=[193, 3137, 197, 2311, 3719, 73, 137, 331, 523, 1931, 719, 337, 211, 23, 1117, 223, 1123, 229, 37, 293, 2917, 1319, 1129, 233, 173, 3119, 113, 53, 373, 311, 313, 1913, 1723, 317]
smallest (a) = 23
largest (b) = 3719
Therefore, the last number of a Fibonacci series i.e. 34th Fibonacci number in the series that has 23 and 3719 as the first 2 numbers is 13158006689
Example 2
Input
30 70
Output
2027041
Explanation
1st prime list=[31, 37, 41, 43, 47, 53, 59, 61, 67]
2nd prime list generated form combination of 1st prime list = [3137, 5953, 5347, 6761, 3761, 4337, 6737, 6131, 3767, 4759, 4153, 3167, 4159, 6143]
smallest prime in 2nd list=3137
largest prime in 2nd list=6761
Therefore, the last number of a Fibonacci series i.e. 14th Fibonacci number in the series that has 3137 and 6761 as the first 2 numbers is 2027041
The code i did is:
def isPrime(num): #function to check for prime Number
if(num>1):
flag=0
for i in range(2,num):
if(num%i==0):
flag=1
break
if(flag==0):
return True #it is a prime number
else:
return False
else:
return False
n,m=map(int,input().split())
first=[int(x) for x in range(n,m) if (isPrime(x))] #first list that contains prime numbers between n and m
second=[]
for i in first:
for j in first:
if(i!=j):
second.append(str(i)+str(j))
prime=list(set([int(x) for x in second if isPrime(int(x))]))
a=min(prime)
b=max(prime)
fib=[a,b]
for i in range(len(prime)-2):
c=a+b
a=b
b=c
fib.append(c)
print(int(fib[len(prime)-1]))
Prime Fibonnaci
Problem Description
Given two numbers n1 and n2
Find prime numbers between n1 and n2, then
Make all possible unique combinations of numbers from the prime numbers list you found in step 1.
From this new list, again find all prime numbers.
Find smallest (a) and largest (b) number from the 2nd generated list, also count of this list.
Consider smallest and largest number as the 1st and 2nd number to generate Fibonacci series respectively till the count (number of primes in the 2nd list).
Print the last number of a Fibonacci series as an output
Constraints
2 <= n1, n2 <= 100
n2 - n1 >= 35
Input Format
One line containing two space separated integers n1 and n2.
Output
Last number of a generated Fibonacci series.
Timeout
1
Test Case
Example 1
Input
2 40
Output
13158006689
Explanation
1st prime list = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
Combination of all the primes = [23, 25, 27, 211, 213, 217, 219, 223, 229, 231, 32, 35, 37, 311, 313, 319, 323, 329, 331, 337, 52, 53, 57, 511, 513, 517, 519, 523, 529, 531, 537, 72, 73, 75, 711, 713, 717, 719, 723, 729, 731, 737, 112, 113, 115, 117, 1113, 1117, 1119, 1123, 1129, 1131, 1137, 132, 133, 135, 137, 1311, 1317, 1319, 1323, 1329, 1331, 1337, 172, 173, 175, 177, 1711, 1713, 1719, 1723, 1729, 1731, 1737, 192, 193, 195, 197, 1911, 1913, 1917, 1923, 1929, 1931, 1937, 232, 233, 235, 237, 2311, 2313, 2317, 2319, 2329, 2331, 2337, 292, 293, 295, 297, 2911, 2913, 2917, 2919, 2923, 2931, 2937, 312, 315, 317, 3111, 3113, 3117, 3119, 3123, 3129, 3137, 372, 373, 375, 377, 3711, 3713, 3717, 3719, 3723, 3729, 3731]
2nd prime list=[193, 3137, 197, 2311, 3719, 73, 137, 331, 523, 1931, 719, 337, 211, 23, 1117, 223, 1123, 229, 37, 293, 2917, 1319, 1129, 233, 173, 3119, 113, 53, 373, 311, 313, 1913, 1723, 317]
smallest (a) = 23
largest (b) = 3719
Therefore, the last number of a Fibonacci series i.e. 34th Fibonacci number in the series that has 23 and 3719 as the first 2 numbers is 13158006689
Example 2
Input
30 70
Output
2027041
Explanation
1st prime list=[31, 37, 41, 43, 47, 53, 59, 61, 67]
2nd prime list generated form combination of 1st prime list = [3137, 5953, 5347, 6761, 3761, 4337, 6737, 6131, 3767, 4759, 4153, 3167, 4159, 6143]
smallest prime in 2nd list=3137
largest prime in 2nd list=6761
Therefore, the last number of a Fibonacci series i.e. 14th Fibonacci number in the series that has 3137 and 6761 as the first 2 numbers is 2027041
from itertools import permutations
def isPrime(n):
for i in range(2,n):
if n%i==0:
return False
else:
return True
def listPrime(n1,n2):
lis=[]
for ele in range(n1,n2+1):
if isPrime(ele)==True:
lis.append(ele)
return lis
def returnPrime(lis):
r=[]
for ele in lis:
if isPrime(ele)==True:
r.append(ele)
return r
def fibo(mi,ma,c):
f=mi
s=ma
res=[]
res.append(f)
res.append(s)
for i in range(2,c):
next=f+s
res.append(next)
f,s=s,next
return res[-1]
def main(n1,n2):
primeNo=listPrime(n1,n2)
comb=permutations(primeNo,2)
r=[]
for ele in comb:
r.append(int(str(ele[0])+str(ele[1])))
comb2=returnPrime(r)
count=len(comb2)
mini=min(comb2)
maxi=max(com2)
res=fibo(mini,maxi,count)
return res
if __name__=="__main__":
lis=list(map(int,input().split()))
lis[0]=n1
lis[1]=n2
res=main(n1,n2)
print(res)
Please help me write the right solution to the code
Also help me optimize it so it runs in below 1 seconds
Profile in which method most time is spent. A wild guess would be isPrime(..). So try to optimize that.
Speedup of 2 by checking even separately and than only check in the loop only odd numbers.
1b. You can improve this even more by storing a list of the first m primes and
check them up front.
you could keep found primes up to a certain value and every number smaller than the highest of your primes that is not in the set of your primes is no prime.
There are a lot of clever ways to implement isPrime(...) just google it and you will find a vast amount of optimization ideas for it.
def check_prime(x):
if x&1 == 0: return 0
for i in range(3,int(x**0.5)+1,2):
if x%i==0: return 0
return 1
n1,n2 = 30,70
min = 9789
max = 23
count = 0
freq = {}
if n1&1 == 0:
l = [i for i in range(n1+1,n2+1,2) if check_prime(i)]
else:
l = [i for i in range(n1,n2+1,2) if check_prime(i)]
if n1 == 2: l = [2] + l
for x in l:
for y in l:
if x != y:
n = int(str(x)+str(y))
if n not in freq:
if check_prime(n):
freq[n] = 1
if n<min: min = n
elif n>max: max = n
count += 1
while count>1:
min,max = max,min+max
count -= 1
print(min)
# Primality Testing with the Rabin-Miller Algorithm
import random
def rabinMiller(num):
# Returns True if num is a prime number.
s = num - 1
t = 0
while s % 2 == 0:
# keep halving s while it is even (and use t
# to count how many times we halve s)
s = s // 2
t += 1
for trials in range(5): # try to falsify num's primality 5 times
a = random.randrange(2, num - 1)
v = pow(a, s, num)
if v != 1: # this test does not apply if v is 1.
i = 0
while v != (num - 1):
if i == t - 1:
return False
else:
i = i + 1
v = (v ** 2) % num
return True
def isPrime(num):
# Return True if num is a prime number. This function does a quicker
# prime number check before calling rabinMiller().
if (num < 2):
return False # 0, 1, and negative numbers are not prime
# About 1/3 of the time we can quickly determine if num is not prime
# by dividing by the first few dozen prime numbers. This is quicker
# than rabinMiller(), but unlike rabinMiller() is not guaranteed to
# prove that a number is prime.
lowPrimes = [[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]]
if num in lowPrimes:
return True
# See if any of the low prime numbers can divide num
for prime in lowPrimes:
if (num % prime == 0):
return False
# If all else fails, call rabinMiller() to determine if num is a prime.
return rabinMiller(num)
def generateLargePrime(keysize=1024):
# Returns a random prime number of keysize bits in size.
while True:
num = random.randrange(2**(keysize-1), 2**(keysize))
if isPrime(num):
return num
I am creating a Python program that will tell you if a number is prime or not. It is basically the Rabin Miller Algorithm, but on line 60, my program stops and I get the error:
TypeError: unsupported operand type(s) for %: 'int' and 'list'.
This is line 60:
lowPrimes = [[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, ...]]
What am I doing wrong?
Your lowPrimes variable is a list of lists, so when you say for prime in lowPrimes, prime is a list, so you can't modulus an int by a list. Try changing lowPrimes = [[...]] to lowPrimes = [...] (remove one layer of brackets).
The error message is pretty instructive here. It's saying that you are trying to apply the % operator to an int and a list. Since you also have the line number you can see the expression it's referring to and that prime must have been a list.
Your lowPrimes array is defined in a wrong way. You want it to be a list of numbers, but instead it is a list of lists of numbers (outer list containing only a single element). This causes the error you see when you iterate over all the elements of lowPrimes and check if your number is divisable by that element of lowPrimes. To fix it, remove outer square brackets:
lowPrimes = [[2, 3, 5, 7, 11, 13, 17, 19, ... 997]]
=>
lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19, ... 997]