Finding Divisors (Codewars Issue) - python

I'm doing a Codewars problem that states:
Create a function named divisors/Divisors that takes an integer n > 1
and returns an array with all of the integer's divisors(except for 1
and the number itself), from smallest to largest. If the number is
prime return the string '(integer) is prime'
I came up with the code:
def divisors(integer):
newlist = []
for x in range(2, integer):
if integer%x==0:
newlist.append(x)
if len(newlist) == 0:
return str(integer) + " is prime"
return newlist
I feel like this should work, and it does for most of the tests, but whenever the first divisor is odd, it doesn't work. For example, 15 and 9 don't work. I know this isn't the optimal way to do this, but I was just wondering why it works for some numbers and doesn't for others.

Your indentation was wrong:
def divisors(integer):
newlist = []
for x in range(2, integer):
if integer%x==0:
newlist.append(x)
if len(newlist) == 0: # this _was_ being executed after just the first iteration
return str(integer) + " is prime"
return newlist
works

And also one thing instead of len(newlist)==0 you can just do not newlist:
def divisors(integer):
newlist = []
for x in range(2, integer):
if integer%x==0:
newlist.append(x)
if not newlist:
return str(integer) + " is prime"
return newlist
print(divisors(15))

Your second if statement is within the for loop so it returns while evaluating x = 2.
Move it out of the for loop and it should work.

You may use
for x in range(2, (integer//2)+1):
instead of
for x in range(2, integer):
to cut the time required into half.
A divisor greater than integer/2 cannot yield the desired result.

Related

Python print non-prime numbers

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

Python: Create a list of all four digits numbers with all different digits within it

I was wondering if there is any easier way to achieve what this code is achieving. Now the code creates all 4-digits number in a list (if the number starts with a 0 is doesn't count as a 4-digit, for example 0123) and no digit is repeated within the number. So for example 1231 is not in the list. Preferable I want a code that does what this one is doing but a depending on what argument N is given to the function upon calling it creates this kind of list with all numbers with N digits. I hope this wasn't impossible to understand since Im new to programing.
def guessables():
'''creates a list of all 4 digit numbers wherest every
element has no repeating digits inside of that number+
it doesn't count as a 4 digit number if it starts with a 0'''
guesses=[]
for a in range(1,10):
for b in range(0,10):
if a!=b:
for c in range(0,10):
if b!=c and a!=c:
for d in range(0,10):
if c!=d and d!=b and d!=a:
guesses.append(str(a)+str(b)+str(c)+str(d))
return guesses
This can be expressed more easily.
def all_digits_unique(number):
# `set` will only record unique elements.
# We convert to a string and check if the unique
# elements are the same number as the original elements.
return len(str(number)) == len(set(str(number)))
Edit:
def guesses(N):
return filter(all_digits_unique, range(10**(N-1), 10**N))
print guesses(4)
I'd use itertools for this which is in my opinion the simplest generic answer:
import itertools
def guessables(num):
guesses = []
for p in itertools.permutations(xrange(10),num):
if p[0] != 0:
guesses.append(''.join(map(str, p)))
return guesses
Simply call this function with guessables(4) and get a list with all the numbers you want.
You can do in one line:
print([str(a)+str(b)+str(c)+str(d) for a in range(1,10) for b in range(0,10) if a!=b for c in range(0,10) if b!=c and a!=c for d in range(0,10) if c!=d and d!=b and d!=a])
Try the following:
def guessables(n):
''' Returns an array with the combination of different digits of size "n" '''
if n > 10:
raise ValueError("The maximum number of different digits is 10.")
elif n < 1:
raise ValueError("The minimum number of digits is 1.")
else:
results = []
for i in range(1, 10):
_recursiveDigit([i], n, results)
return results
def _formatDigit(l):
''' Return a formated number from a list of its digits. '''
return "".join(map(str, l))
def _recursiveDigit(l, n, results):
''' Recursive function to calculate the following digit. '''
if len(l) < n:
for i in range(0, 10):
if i not in l:
_recursiveDigit(l + [i], n, results)
else:
results.append(_formatDigit(l))
The functions that are prefixed with an underscore(_) should not be called from outside of this script. If you prefer to have the result as something different than an array of strings, such as an array of ints for example, you can change the _formatDigit() function as follows:
def _formatDigit(l):
''' Return a formated number from a list of its digits. '''
return int("".join(map(str, l)))
c=list(range(10))
print c
def fun(n,k,i,getnum): # function , result in getnum
if n==0:
if k not in getnum and len(set(list(k)))==len(k) and k[0]!='0':
getnum.append(k)
return
if i>=len(c):
return
fun(n-1,k+str(c[i]),0,getnum)
fun(n,k,i+1,getnum)
getnum=[]
d=fun(4,"",0,getnum)
print getnum
These types of problems are easily solved with recursion.
def gen(num, n, saveto):
if len(num) == 1 and num[0] == '0':
return
if len(num) == n:
saveto.append(int(''.join(num)))
return
for i in range(0, 10):
i= str(i)
if i not in num:
gen(num+[i], n, saveto)
saveto= []
# generate 4 digit numbers
gen([], 4, saveto)
print(saveto)
Here I'm using the list num to construct the numbers by placing one digit at each call. When there are four digits added, it stores the number to the saveto list.
Edit: Here's a version of the above function that returns the list of numbers instead of appending them to a list.
def gen(num, n):
if len(num) == 1 and num[0] == '0':
return []
if len(num) == n:
return [int(''.join(num))]
ans = []
for i in range(0, 10):
i= str(i)
if i not in num:
ans.extend(gen(num+[i], n))
return ans
saveto= gen([], 4)
print(saveto)
numPool = []
for i in range(0, 10):
for j in range(0, 10):
for k in range(0,10):
for l in range(0,10):
if i != j and i != k and i != l and j != k and j != l and k != l :
numPool.append(str(i) + str(j) + str(k) + str(l))
This works, but keep in mind that this will also add "0123" or "0234" to the list as well. If you do not want the numbers that are starting with zero, you might want to add "i != 0" to the if query. Hope it helps.
I try to write it clear for absolute beginers ^^ Ofcourse it is possible to make it faster and shorter if you use combianations and advance array methods.
def f(n)
s = list(range(10**(n-1), 10**n))
number_list = []
for ss in s:
test_list = []
a = ss
while ss:
if ss % 10 in test_list:
break
test_list.append(ss % 10)
ss = ss // 10
if len(test_list) == n:
number_list.append(a)
return number_list
print(f(4))
This would sovlve the problem, without repeating digits:
from itertools import permutations
myperm = permutations([0,1,2,3,4,5,6,7,8,9],4)
for digits in list(myperm):
print(digits)
How about this?
def check_count(num):
if isinstance(num, str) == False:
num = str(num) # Convert to str
if len(num) == 1: # If total length number is single, return False
return False
return any(num.count(x) > 1 for x in num) # Check here
Return False if numbers all different, else return True
Usage:
# Get all numbers has all different. (1000-9999)
[x for x in range(1000, 10000) if check_count(x) == False]

Python prime number list

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.

Prime factorization code produces IndexError with certain numbers

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

How to create a piece of code which checks a number for its greatest prime factor?

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.

Categories

Resources