Confusion with Python set() [duplicate] - python

This question already has answers here:
How does all() in python work on empty lists
(5 answers)
Closed 2 years ago.
I found this code to generate prime number in Python3:
def gen_primes(N):
"""Generate primes up to N"""
primes = set()
for n in range(2, N):
if all(n % p > 0 for p in primes):
primes.add(n)
yield n
Here I have confusion with the line if all(n % p > 0 for p in primes). Since primes is initially blank, so the code inside "if" should never execute.
To become confident, I tried the code below and it is not executing the code inside the "for".
primes = set()
n=2
print("---------Outside For Loop--------")
for p in primes:
print("---------Inside For Loop------")
if all(n%p>0):
print("Hello")
else:
print("No Way")
So I need expert help here to understand how this prime number generator working in this case?

Your test doesn’t demonstrate the issue because the function all is what you should inspect:
all([])
>>>True
By default all return Trie for empty lists, because unless all() finds a false In a list it returns true.

the all() function returns True if all items in an iterable are True, otherwise it returns False. If the iterable object is empty, the all() function also returns True.
I rewrote your function by replacing all() with v (which means validity) if the number is not prime (in other words it is not divisible by any number less than the number itself) v = 0 and is not included in the primes set.
def gen_primes(N):
primes = set()
for n in range(2,N+1):
v = 1
for nn in range(2,n):
if(n%nn == 0):
v = 0
break
if v: primes.add(n)
return primes
print(gen_primes(23))

Related

What is wrong with my prime filtering code? It won't return the proper list

I wrote a function filter_primes that is supposed to (aptly) filter out prime numbers from a given list and output a new list of just the primes. When I run this example I get>>> [9].
My brain is boggled. Can someone point me in the right direction?
n = 2
def is_prime(num):
global n
if num%n != 0 and n<num:
n = n + 1
is_prime(num)
elif n == num:
return True
else:
return False
def filter_primes(list1):
list2 = []
for i in list1:
if is_prime(i):
list2.append(i)
print(list2)
filter_primes([7, 9, 3, 9, 10, 11, 27])
The problem is in your is_prime function. Since you are doing it recursively, you want to separate it into:
Handle the base cases:
You find an n that evenly divides num, then num isn't prime
You end up with an n bigger than num, then num is prime
Otherwise, call your function recursively with n+1 and return that value.
One way to get around using the global n (which then gets overwritten each time a new larger is used), is to have is_prime have a default starting value for n)
For example,
def is_prime(num, n=2):
if n >= num: # This could be made into sqrt(num) if you're trying to optimize this
return True
if num % n == 0:
return False
return is_prime(num, n+1)
The way I tackled this was to open the code up in an IDE (IntelliJ), and then step through the code line by line using an intergrated debugger. This will help you visualize what is going on. Else try printing out variables inside the function.
You first problem is that you are using global n. This works perfectly fine for the first number 7, but this number doesn't get reset for the second number 9. Thus what is happening is that is_prime(9) is only testing against division of 8 (which is why it returns true)
This could potentually be done in a loop rather than using recursion, but since you are using recursion, n (as internal state) can be handled by passing this as a function parameter with a default. This will reset n for each top level call for n.
Also as you are recursively calling is_prime(), you need return is_prime() to ensure the boolean returned from the top of the stack gets returned when you unwind back to the bottom of the stack for the original caller.
Your code accidently worked for is_prime(9) because your logic was only testing for 8, thus could return without recusion.
Here is working code:
def is_prime(num, n=2):
if num % n != 0 and n < num:
n = n + 1
return is_prime(num, n)
elif n == num:
return True
else:
return False
def filter_primes(list1):
list2 = []
for i in list1:
if is_prime(i):
list2.append(i)
return list2
print( filter_primes([7, 9, 3, 9, 10, 11, 27]) )
$ primes.py
[7, 3, 11]
Also you might find it intresting to do a little reading up on prime number search algorithms.
A few simple optimizations:
Except for 2, all prime numbers are odd (so you can return False instantly)
Sieve of Eratosthenes extends this further
Technically you only need to search upto sqrt(num)
Read up on memoization (aka dynamic programming), as you can cache results from previous function calls
Add python type hints and write documention for your functions (your future self will thank you when you return the code in a month)
Consider a new usecase:
generate the entire sequence of prime numbers (you will start to notice performance issues here)
Add a timer, or use a profiler inside your IDE. Compare how fast the code runs, especially for large numbers. Do these suggested optimizations speed things up?

Find duplicate in list using built-in functions only [duplicate]

This question already has answers here:
check for duplicates in a python list
(7 answers)
Closed 4 years ago.
I am a TOTAL Noob so please be gentle!
I have written this code:
def sorted_has_duplicate(numbers):
numbers.sort()
duplicate = False
for num in range(len(numbers)-1):
if numbers[num] == numbers[num + 1]:
duplicate = True
break
return duplicate
The code runs fine and it does what it is supposed to do which is find the first duplicate value in a list if any and return True or False.
My question is how can I have the same function perform the same task if the list is not sorted (sorting is not allowed) and i can only use built in python functions?
Collect nums in a set as you iterate:
def has_duplicate(numbers):
seen = set()
for num in numbers:
if num in seen:
return True
seen.add(num)
return False
You can also shorten this down to:
def has_duplicate(numbers):
return len(numbers) != len(set(numbers))
This simply checks whether the list has as many elements as its set which by definition has no duplicates.
Note that both these set-based solutions run in linear time because of a set's O(1) contains-check. The naive brute force approach of searching for each element in the list remainder
def has_duplicate(numbers):
for i, num in enumerate(numbers):
if num in numbers[i+1:]:
return True
return False
is quadratic because of a list's O(N) contains-check.

Printing out prime numbers till N using recursion

L=[]
def Prime(N):
a=0
for i in range(2,N):
if N%i==0:
a+=1
if a>0:
return False
else:
return True
def PrimesList(N):
if N==2:
L.append(2)
elif Prime(N):
L.append(N)
return PrimesList(N-1)
else:
return PrimesList(N-1)
L.reverse()
print L
If I use it one time, it gives the correct answer. But L is being saved in global environment. How can I bring it inside loop when using recursion? The question might be basic for most of you but I am new to Python. I am supposed to print the prime numbers till N.
I would do it as a second parameter, using None to avoid this common issue:
def PrimesList(N, L=None):
if L is None:
L = []
...
Then just include L in the recursive call and make sure you return L from the end of he recursion.
To print the first N prime numbers you can just print the first N-1 prime numbers and add next prime. However to compute next prime the list of numbers is also useful so in addition to print it just return the list:
def printFirstPrimes(N):
if N == 1:
result = [2]
else:
result = printFirstPrimes(N-1)
# ... compute next prime here ...
result.append(next_prime)
print result
return result
Note that this is not the best approach with Python, deep recursion is not very efficient and tail call optimization is not implemented in the reference implementation CPython.

Could someone explain this code for me?

Can someone explain this piece of code for me, in simple terms.
prompts = ("Enter Strength Attribute, between 1 and 50: ", "Enter Skill Attribute, between 1 and 50: ") # I already now this so no need to explain it
answers = [int(input(p)) for p in prompts]
if not all(0 < a <=50 for a in answers):
# other code here
Is it a generator?
And how does it work?
Thanks in advance for any answers.
You have a list comprehension and a generator expression.
The list comprehension is:
[int(input(p)) for p in prompts]
and produces a list of integers from a list of prompts, asking the user for a series of numeric values.
It could also be expressed as:
answers = []
for p in prompts:
result = int(input(p))
answers.append(result)
Next is:
(0 < a <=50 for a in answers)
which is the generator expression. It tests if each of the numbers is a value between 0 (exclusive) and 50 (inclusive).
The all() function will loop over the generator expression one result at a time, and will return False the moment one of those results is False, or True when it exhausts the generator results and no False values were found.
You could replace the if all(...) test with:
result = True
for a in answers:
if not 0 < a <= 50:
result = False
break
if result:
This would achieve the same effect; loop over answers one by one, but stop looping early if any of the tests was False (not a number greater than 0 and smaller than or equal to 50).
answers = [int(input(p)) for p in prompts]
This is a list comprehension. It could be written as a for loop like this:
answers = []
for p in prompts:
resp = int(input(p))
answers.append(resp)
if not all(0 < a <=50 for a in answers):
This is a generator, wrapped in all (a built in function that returns whether all elements are true) You could write that as a function:
def all(answers):
for a in answer:
if not 0 < a <= 50:
return False # note this short-circuits, stopping the loop
return True
It is a list comprehension.
The first line does exactly the same as:
answers=[]
for p in prompts:
a=int(input(p))
answers.append(a)
The part of the second line behind the if condition does exactly the same as:
for a in answers:
if a <= 0 or a > 50:
return False
return True
for p in prompts
enumerates the prompts
int(input(p))
asks the user for an input, using the p as a prompt, then try to coerce the input as an int
answers = [...]
makes answers a list of all the inputs converted in ints (this is a comprehension list)
(0 < a <=50 for a in answers)
This is a generator. It creates an iterable containing the test 0 < a <=50 for each value in the answers list
if not all(...)
Tests all elements in the generator. if any one is false, do other code

find primes function

I have a function:
def containsNoDivisor(n, ps):
'''n is an integer and ps is a list of integers. Returns True if
and only if there is no integer in ps that divides n. '''
for p in ps:
if n % p == 0:
return False
print True
Then I need to create another function, that computes a list of primes < n, from the function above. So far I have:
def findPrimes(n):
primes = [2]
for i in range(3,n):
if containsNoDivisor(i, primes):
primes.append(i)
return primes
But it is returning True's instead of the primes?
It looks like you're printing True instead of returning it in your containsNoDivisor function. It should look like this:
def containsNoDivisor(n, ps):
'''n is an integer and ps is a list of integers. Returns True if
and only if there is no integer in ps that divides n. '''
for p in ps:
if n % p == 0:
return False
return True
The print statement simply outputs the value to the console - if you're trying each function in the interactive shell, it's an easy mistake to make. return will actually take the value and pass it back to whatever called it, allowing data to be used outside of the function that created or processed it.
def containsNoDivisor(n, ps):
'''n is an integer and ps is a list of integers. Returns True if
and only if there is no integer in ps that divides n. '''
for p in ps:
if n % p == 0:
return False
print True
^^^^^
should be return
You are testing every number from 3 to n. You don't need to test even numbers since all evens > 2 are composite. Try stepping 2 rather than 1: 3, 5, 7, 9, 11, ...

Categories

Resources