find primes function - python

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, ...

Related

Writing a function that returns true if an integer is between two numbers in Python

I have attempted to write a function that has a for loop that returns True if my input was between two numbers. this is what I wrote:
def func(x):
x = list(range(0,1000))
for n in x:
if 90 <= n <= 110:
return True
else:
return False
To my understanding x is between 0 to 10000 and the characters in x which are n, should return True if my input is between 90-110 and false otherwise.
However, this does not work.
I did further research and I found that the following function works
which is:
def myfunc(n):
return (90 <= n <= 110)
This function will return true if n is between 90-110
Why is the function that has a for loop did not work ?
When using return you get out of the function scope. for it achieve what you want to do you can use a list that contains the boolean values of each case and return that array.
You can try using the range function:
def myfunc(n):
lower_limit = 90
upper_limit = 110
number_range = range(lower_limit, upper_limit)
return (n in number_range)
The problem in your for is that you're returning False first time a number that's not in the range. And because you're creating a list of number from 0 to 1000, this means that first number will be 0.
Your script will check n=0 against 90<=n<=110. This is False so it will return False. Returnning a value will end the execution of that function, so the for loop is gonna be stopped at the first iteration returning False.
You can read here about return

Checking if a number has any repeated elements

I have been working on spliting integers into the digits they are comprised of and then checking whether there are any repeated numbers in the list. However the code seems to always say there are no repeated numbers, even if there are.
My Code:
def repeatCheck(myList, repeatedNumber):
seen = set()
for number in myList:
if number in seen:
repeatedNumber = True
seen.add(number)
return repeatedNumber
def numberWorks(number, finalNumber):
digits = [int(n) for n in str(number)]
repeatedNumber = False
repeatCheck(digits, repeatedNumber)
if repeatedNumber == False:
print(number, "succeeded repeatedNumber")
found = True
else:
print(number, "failed repeatedNumber")
pass
return number
number = 1000000000
while found == False:
numberWorks(number, finalNumber)
number += 1
print(finalNumber)
With input number 1000000000, the output should be 1023456789
Please let me know of anything that could be done to solve it, or if the code I have given is not enough.
Thank you.
When you call the function repeatCheck() you don't pass a reference to the variable repeatedNumber, so any changes to the variable do not affect the original definition of repeatedNumber. Therefore, the repeatedNumber defined in numberWorks() is never updated.
what you could do instead is assign the return value of repeatCheck to repeatedNumber.
repeatedNumber = False
repeatedNumber = repeatCheck(digits)
and rewrite repeatCheck to return True or False upon seeing a repeat:
def repeatCheck(myList):
seen = set()
for number in myList:
if number in seen:
return True
seen.add(number)
return False
This way you circumvent the ambiguity of reusing the variable name repeatedNumber
If you would like to check for repeated digits inside a number here's a quick way to do it that returns a boolean.
def noRepeatedDigits(number:int) -> bool:
return all([str(number).count(i) == 1 for i in set(str(number))])
print(noRepeatedDigits(12344))
print(noRepeatedDigits(1234))
False #indicates it failed the check
True #indicates it passed the check
I would simply delete all your code and do this.
def repeatCheck(repeatedNumber):
numbersdub = list(str(repeatedNumber))
numbers = set(numbersdub)
for num in numbers:
numbersdub.remove(num)
return set(numbersdub)
print(repeatCheck(78788))
This will give you a set of all dubbels.
Alternative one-line solution:
finalNumber = next(n for n in range(1000000000, 2000000000) if len(set(s := str(n))) == len(s))
print(finalNumber)
# 1023456789
Explanation: len(str(n)) is the number of digits of n, whereas len(set(str(n))) is the number of unique digits of n. These two quantities are equal if an only if n doesn't have repeated digits.
The whole thing is wrapped in an iterator, and next( ) returns the first value of the iterator.

Confusion with Python set() [duplicate]

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))

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?

Sum of all arguments

This is a codewars challenge where you have to return the sum of the given arguments.
Instructions:
Calculate the sum of all the arguments passed to a function.
Note: If any of the arguments is not a finite number the function should return false/False instead of the sum of the arguments.
Here's my code:
def sum_all(*args):
sum = 0
for str(num) in args:
if not num.isdigit():
return False
else:
int(sum) += num
return sum
Currently I'm getting this error:
File "", line 9
SyntaxError: can't assign to function call
That error message is actually happening in two places:
Here:
for str(num) in args:
and here:
int(sum) += num
You cannot cast to string and int the way you are attempting to.
What you should do instead, is keep your iteration as:
for num in args:
Then, you can check if digit by doing this:
if not str(num).isdigit():
Finally, when you get to summing everything, simply cast num to int(num) to handle the case if you pass something like [1, 2, '3', 4] (not the 3 as a string):
sum += num
So, with that in mind, your code will look like this:
def sum_all(*args):
sum = 0
for num in args:
if not str(num).isdigit():
return False
else:
sum += int(num)
return sum
However, as you pointed out in your comment, there is a test case for negative numbers. This is where the above code breaks. Because, negative numbers as a string:
"-343"
Do not pass isdigit.
If you put this in your interpreter, it will return False:
"-343".isdigit()
So, with all this in mind, you can actually further simplify your code when you remove that to just have this:
def sum_all(*args):
try:
return sum(int(i) for i in args)
except:
return False
Demo:
print(sum_all(1,2,3,4,5))
Outputs:
15
First of all, don't overwrite existing functions such as sum. Use a different variable name (e.g. sum_). Second, your problem is on the for str(num) in args line. This needs to be for num in args:, with a modification of the following line for str(num).
def sum_all(*args):
sum_ = 0
for num in args:
if not str(num).isdigit():
return False
else:
sum_ += float(num)
return sum_
>>> sum_all('a', 2)
False
>>> sum_all(1, 2)
3.0
>>> sum_all(1, 2, '4')
7.0
Here is an alternative approach to coding the function that uses a generator comprehension to try and sum the arguments but returns False if it fails:
def sum_all2(*args):
try:
return sum(i for i in args)
except:
return False
>>> sum_all2(1, 2, '4.5')
False
>>> sum_all2(1, 2, '4') # I argue that '4' is a string, not a finite number.
False
>>> sum_all2(1, 2)
3
>>> sum_all2(1, 2, 3.5)
6.5
>>> sum_all2(1, 2, -3.5)
-0.5
You're overthinking this. There are two parts to this to note:
sum is a function that already takes in a collection and gives you its sum.
You want to reject the collection if none of them are numeric types.
Here's a start: this particular method will reject if none of the values are int. I leave expanding this out to float types as an exercise for the reader.
def sum_or_reject(li):
return sum(li) if all([isinstance(i, int) for i in li]) else False
The minimal change to make your logic run is:
def sum_all(*args):
sum = 0
for s in args:
num = str(s)
if not num.isdigit():
return False
else:
sum += int(num)
return sum
The line number in the question is misleading, and there are two issues: First, you need a variable for the iteration. Second, you need a variable for the += assignment. In both cases you try to apply a cast, bust the result of that would not longer be a variable and thus cannot be used as target for the assignment.
Likewise a minimal change to your code:
def sum_all(*args):
try:
return sum(int(i) for i in args)
except:
return False
print(sum_all(10,'-1',10))

Categories

Resources