Python List Indexing Error - python

def getPrimeList(check):
storedprimes = []
i = 2
while i <= check:
if isPrime(check):
storedprimes = storedprimes + [i]
i = i + 1
return storedprimes
def getPrimeFact(check):
primelist = getPrimeList(check)
prime_fact = []
i = 0
while check !=1:
if check%primelist[i]==0:
prime_fact=prime_fact+[primelist[i]]
check = check/primelist[i]
i = i + 1
if i == len(primelist):
i = 0
return prime_fact
def getGCF(checks):
a=0
listofprimefacts=[]
while a<len(checks):
listofprimefacts=listofprimefacts+[getPrimeFact(checks[a])]
a=a+1
b=0
storedprimes=[]
while b<len(primefactlist):
c=0
while c<len(listofprimefacts[b]):
if listofprimefacts[b][c] not in storedprimes:
storedprimes=storedprimes+[listofprimefacts[b][c]]
c=c+1
b=b+1
prime_exp=[]
d=0
while d<len(storedprimes):
prime_exp=prime_exp+[0]
d=d+1
e=0
while e<len(storedprimes):
f=0
while f<len(listofprimefacts):
if f==0:
prime_exp[e]=listofprimefacts[f].count(storedprimes[e])
elif prime_exp[e]-(listofprimefacts[f].count(storedprimes[e]))>0:
prime_exp[e]=listofprimefacts[f].count(storedprimes[e])
f=f+1
e=e+1
g=0
GCF=1
while g<len(primelist):
GCF=GCF*(storedprime[g]**prime_exp[g])
g=g+1
return GCF
I am creating a program that will use these functions for the purpose of calculating fractions; however, after testing my GCF function in the shell I keep getting a list indexing error. I have no idea, where the error is coming from considering im 99% sure there is no problems with my indexes, usually i would not post such a "fixable" problem in SO but this time i just have no idea what the problem is, thanks again.
Oh and heres the exact error
File "<pyshell#1>", line 1, in <module>
getGCF(checks)
File "E:\CompProgramming\MidtermFuncts.py", line 31, in getGCF
listofprimefacts=listofprimefacts+[getPrimeFact(checks[a])]
File "E:\CompProgramming\MidtermFuncts.py", line 20, in getPrimeFact
if check%primelist[i]==0:
IndexError: list index out of range

You might want to re-think how you attack this problem. In its current form, your code is really hard to work with.
Here's how I'd do it:
def is_prime(n):
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
def prime_factors(number):
factors = []
for i in range(2, number / 2):
if number % i == 0 and is_prime(i):
factors.append(i)
return factors
def gcf(numbers):
common_factors = prime_factors(numbers[0])
for number in numbers[1:]:
new_factors = prime_factors(number)
common_factors = [factor for factor in common_factors if factor in new_factors]
return max(common_factors)
This line right here:
common_factors = [factor for factor in common_factors if factor in new_factors]
Is a list comprehension. You can unroll it into another for loop:
temp = []
for factor in common_factors:
if factor in new_factors:
temp.append(factor)
common_factors = list(temp) # Pass by value, not by reference

You mixed up i and check in your getPrimeList() function; you test if check is a prime, not i; here is the correct function:
def getPrimeList(check):
storedprimes = []
i = 2
while i <= check:
if isPrime(i): # *not* `check`!
storedprimes = storedprimes + [i]
i = i + 1
return storedprimes
This, primelist will be set to an empty list (as getPrimeList(check) returns an empty list) and your primelist[i] (for any i) will fail with an index error.
Another way for primelist to be empty is when isPrime() never returns True; you don't show us that function to verify it.
Your next error is in getGCF(); you define a listofprimefacts variable (a list) first, but later refer to a non-existing primefactlist variable, leading to a NameError. The next name error is going to be primelist further in that function.
You really want to re-read the Python tutorial; you are missing out on many python idioms in your code; specifically on how to create loops over sequences (hint: for check in checks: is easier to use than a while loop with an index variable) and how to append items to a list.
My personal toolkit defines this:
from math import sqrt
def prime_factors(num, start=2):
"""Return all prime factors (ordered) of num in a list"""
candidates = xrange(start, int(sqrt(num)) + 1)
factor = next((x for x in candidates if (num % x == 0)), None)
return ([factor] + prime_factors(num / factor, factor) if factor else [num])
which doesn't need a isPrime() test.

Related

generator with conditions in python

which is taken from the predefined interval [a=10000, b=99999]
will fill the list (lst) with a random value, taking into account the following principle: on an even index
The sum of the standing digits is equal to the sum of the standing digits on the odd index
Here is a hit-or-miss generator that works well for numbers in your range:
import random
def even_odd_places(n):
evens = []
odds = []
for i,d in enumerate(str(n),start = 1):
if i % 2 == 0:
evens.append(int(d))
else:
odds.append(int(d))
return evens,odds
def check_condition(n):
e,o = even_odd_places(n)
return sum(e) == sum(o)
def rand_nums(a,b,max_tries = 1000):
tries = 0
while True:
tries += 1
n = random.randint(a,b)
if check_condition(n):
tries = 0
yield n
else:
if tries == max_tries:
return None
For example:
g = rand_nums(10000, 99999)
s = [next(g) for _ in range(10000)]
print(s[:5])
#typical output: [25641, 45980, 38225, 34320, 94380]
Something better than a hit-or-miss approach would require some nontrivial mathematical analysis. There is no easy way to generate all numbers in a given range which satisfy the target condition.

Performance improvement for calculating the powerset of a list of integers

I am trying to compute the powerset of a list of prime numbers. I have already done some research and the prefered way of doing this seems to be using a line like
itertools.chain.from_iterable(itertools.combinations(primes, r) for r in range(2, len(primes) + 1))
and then iterating over all combinations to get the products with math.prod(). All in all, the code currently looks like this:
number = 200
p1 = []
# calculate all primes below specified number
for i in range(2, number + 1):
isPrime = True
for prime in p1:
if i % prime == 0:
isPrime = False
if isPrime:
p1.append(i)
Pp = []
myIterable = itertools.chain.from_iterable(itertools.combinations(p1, r) for r in range(2, len(p1) + 1))
# convert iterable to integer array of products -- The code below is extremely slow and should be improved
for x in myIterable:
newValue = math.prod(x)
if newValue <= number:
Pp.append(newValue)
This works, but it is not feasible for any "number" greater than 100 because of too high execution time. The problem is the last for loop, which takes forever to compute. Everything else performs reasonably well. The powerset has to be constricted to sets, whos products are less or equal to number, as done using the last if statement, or else the memory will explode.
The solution to this problem was to create a pointer array, which crawls through the prime array until the product of the pointed primes gets too high. The needed helper functions can be implemented like this:
def calcProductOfPointers(pointerArray, dataArray):
prod = 1
for pointer in pointerArray:
prod *= dataArray[pointer]
return prod
def incrementPointer(pointerArray, dataArray, threshold):
ret = False
for i in range(1, len(pointerArray) + 1):
index = len(pointerArray) - i
pointerArray[index] += 1
if calcProductOfPointers(pointerArray, dataArray) <= threshold and pointerArray[index] < len(dataArray):
ret = True
break
elif index > 0:
pointerArray[index] = pointerArray[index - 1] + 2
else:
break
return ret
And then the iteration over all powersets can be substituted with this code:
Pp = []
for i in range(2, len(p1) + 1): # start at a minimum of 2 prime factors
primePointers = []
for index in range(i):
primePointers.append(index)
if calcProductOfPointers(primePointers, p1) > number:
break
while calcProductOfPointers(primePointers, p1) <= number:
Pp.append(calcProductOfPointers(primePointers, p1))
if not incrementPointer(primePointers, p1, number):
break

Error when I do the operation p/p+1 + p+1/p considering p a prime in python

So, I wanted to create a simple program that returns a calculation about consecutive primes. First, I create a list that has all of these primes, and then I tried to calculate the result, but this gives me an index out of range. Anyone can help me?
My program:
primes = []
lista = []
somas = []
def isPrimeNumber(number): #Calculate if is or not prime, here is everything ok
for i in range(1, number+1):
if number % i == 0:
lista.append(i)
if len(lista) == 2 or len(lista) == 1:
lista.clear()
return True
else:
lista.clear()
return False
for c in range(1,100):
if isPrimeNumber(c):
primes.append(c)
for t in range(1,len(primes)): #Here is the problem!
somas[t] = primes[t]/primes[t-1] + primes[t-1]/primes[t]
print(primes)
print(somas)
The error:
Traceback (most recent call last):
File "C:\Users\Leleco\Desktop\primos_teom.py", line 19, in <module>
somas[t] = primes[t]/primes[t-1] + primes[t-1]/primes[t]
IndexError: list assignment index out of range
Some remarks:
Your isPrime gives True for 1, while is should return False. Leave out the or len(lista) == 1. See for example this Numberphile video about 1 not being prime.
Better make lista a local variable to isPrime(). That way it doesn't need to be emptied at the end. Local variables only exist inside the function so you don't need to worry about them outside it.
Instead of writing if blabla return True else return False, just use return blabla
You need append to add stuff to somas. Just assigning something to somas[t] before somas is long enough to contain a position for t is not allowed in Python.
def isPrimeNumber(number): #Calculate whether number is prime or not
lista = []
for i in range(1, number+1):
if number % i == 0:
lista.append(i)
return len(lista) == 2
primes = []
for c in range(1,100):
if isPrimeNumber(c):
primes.append(c)
somas = []
for t in range(1,len(primes)):
somas.apppend(primes[t]/primes[t-1] + primes[t-1]/primes[t])
print(primes)
print(somas)
PS: Using zip, the calculation of the sums could also be written as:
for p0, p1 in zip(primes[:-1],primes[1:]):
somas.append(p1/p0 + p0/p1)

Why is this code not running fully? It doesn't run line 53

I made myself an exercise with python since I am new. I wanted to make a rever LMC calculator ( Least common multiple ) but for some reason, something as simple as a print in a loop doesn't seem o work for me. I would appreciate some help since I am stuck on this weird issue for 20 minutes now. Here is the code:
import random
import sys
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
for x in range(lineN + 1):
first, second = guess(count_4_guess, 1, 1)
count_4_guess += 1
print(first + second)
# this ^^^ doesn't work for some reason
Line 57 is in the while loop with count_4_guess. Right above this text, it says print(first_guess + second_guess)
Edit: The code is supposed to take in an int x and then prompt for x values. The outputs are the inputs without x and LMC(output1, output2) where the "LMC" is one of the values. This is done for each of the values, x times. What it actually does is just the first part. It takes the x and prompts for x outputs and then prints them but doesn't process the data (or it just doesn't print it)
Note: From looking at your comments and edits it seems that you are lacking some basic knowledge and/or understanding of things. I strongly encourage you to study more programming, computer science and python before attempting to create entire programs like this.
It is tough to answer your question properly since many aspects are unclear, so I will update my answer to reflect any relevant changes in your post.
Now, onto my answer. First, I will go over some of your code and attempt to give feedback on what could improved. Then, I will present two ways to compute the least common multiple (LCM) in python.
Code review
Code:
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
Notes:
Where are the parameters? It was already mentioned in a few comments, but the importance of this cannot be stressed enough! (see the note at the beginning of my comment)
It appears that you are trying to print each element of a list on a new line. You can do that with print(*my_list, sep='\n').
That while loop is not how you should iterate over the elements of a list. Instead, use a for loop: for element in (my_list):.
Code:
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
Notes:
This is not a correct algorithm for the LCM, since it crashes when both numbers are 0.
The comparison of a and b can be replaced with greater = max(x, y).
See the solution I posted below for a different way of writing this same algorithm.
Code:
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
Notes:
The line num += 1 comes immediately after return first_guess, second_guess, which means it is never executed. Somehow the mistakes cancel each other out since, as far as I can tell, it wouldn't do anything anyway if it were executed.
if lcm(first_guess, second_guess) == values[num - 1]: is completely redundant, since the while loop above checks the exact same condition.
In fact, not only is it redundant it is also fundamentally broken, as mentioned in this comment by user b_c.
Unfortunately I cannot say much more on this function since it is too difficult for me to understand its purpose.
Code:
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
Notes:
As explained previously, print_list() should not be a thing.
lineN should be changed to line_n, or even better, something like num_in_vals.
count_4_add will always be equal to lineN at the end of your for loop.
Building on the previous point, the check if count_4_add >= lineN is useless.
In conclusion, count_4_add and count_4_guess are completely unnecessary and detrimental to the program.
The for loop produces values in the variable x which is never used. You can replace an unused variable with _: for _ in range(10):.
Since your input code is simple you could probably get away with something like in_vals = [int(input(f'Enter value number {i}: ')) for i in range(1, num_in_vals+1)]. Again, this depends on what it is you're actually trying to do.
LCM Implementations
According to the Wikipedia article referenced earlier, the best way to calculate the LCM is using the greatest common denominator.
import math
def lcm(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
This second method is one possible brute force solution, which is similar to how the one you are currently using should be written.
def lcm(a, b):
if a == b:
res = a
else:
max_mult = a * b
res = max_mult
great = max(a, b)
small = min(a, b)
for i in range(great, max_mult, great):
if i % small == 0:
res = i
break
return res
This final method works for any number of inputs.
import math
import functools
def lcm_simp(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
def lcm(*args: int) -> int:
return functools.reduce(lcm_simp, args)
Oof, that ended up being way longer than I expected. Anyway, let me know if anything is unclear, if I've made a mistake, or if you have any further questions! :)

Check if list contains alternating primes and perfect squares

I am just getting started in Python Programming. I had a problem on checking if a given list contains alternating sequence of primes and perfect squares. The list can start with either a prime or a perfect square. I came up with a solution but it's not efficient as it generates unwanted lists. Is this possible with more efficient Python code?
First I'm creating functions to generate a list of primes as well as perfect squares up to the max value of testing list. Functions squaretest() and primecheck():
def squaretest(num):
sqlist=[]
i=1
while i**2 <= num:
sqlist.append(i**2)
i+=1
return sqlist
def primecheck(num):
primelist=[]
for i in range(2,num + 1):
for p in range(2,i):
if (i % p) == 0:
break
else:
primelist.append(i)
return primelist
Then I am dividing the given list into lists of even index and odd index elements and checking all elements of them against the primelist and the squarelist:
def primesquare(l):
if len(l)==1:
primelist = primecheck(l[0])
sqlist = squaretest(l[0])
return (l[0] in primelist) or (l[0] in sqlist)
else:
ol=[]
el=[]
for i in range(0,len(l),2):
ol.append(l[i])
for p in range (1, len(l),2):
el.append(l[p])
primelist = primecheck(max(l))
sqlist = squaretest (max(l))
return((all(x in primelist for x in el)) == True and (all(y in sqlist for y in ol)) == True) or ((all(x in primelist for x in ol)) == True and (all(y in sqlist for y in el)) == True)
It works.
Any suggestions will be really helpful.
You can use sets to check if all members of a list are in another list.
def primesquare(l):
if len(l) == 0:
return True
primelist = set(primecheck(max(l)))
sqlist = set(squaretest(max(l)))
ol = set(l[::2])
el = set(l[1::2])
odds_are_primes = ol.issubset(primelist)
odds_are_squares = ol.issubset(sqlist)
evens_are_primes = el.issubset(primelist)
evens_are_squares = el.issubset(sqlist)
return (odds_are_primes and evens_are_squares) or (odds_are_squares and evens_are_primes)
I came up with a solution but it's not efficient as it generates
unwanted lists.
Assuming the unwanted lists are the two lists representing the even and odd elements, then we can fix that. (Eliminating the primes and squares list is a whole 'nother problem.) Below is my rework of your code -- we don't create addtional lists but rather with a couple of reusable ranges which are objects that produce integer sequences as needed, but not stored in memory.
Your any() design is efficient in that the arguments are generator expressions, not lists, which are computed as needed. As soon as a flaw is found in the array, the whole thing stops and returns False--it doesn't need to process the rest:
def squares(number):
return {x * x for x in range(int(number ** 0.5) + 1)}
def primes(number):
prime_set = set()
for i in range(2, number + 1):
for p in range(2, int(i ** 0.5) + 1):
if (i % p) == 0:
break
else: # no break
prime_set.add(i)
return prime_set
def primesquare(array):
if not array:
return True # define as the problem demands
length, maximum = len(array), max(array)
odd, even = range(0, length, 2), range(1, length, 2)
prime_set, square_set = primes(maximum), squares(maximum)
return all(array[i] in prime_set for i in even) and all(array[i] in square_set for i in odd) or all(array[i] in prime_set for i in odd) and all(array[i] in square_set for i in even)
I admire #AndreySemakin's set-based solution (+1), and use sets above, but his solution generates the same lists you want to eliminate (just in the form of sets).
I came up with this solution:
def primesquare(lst):
# checking if the first element is either perfect square or a prime
if not lst or (not checksquare(lst[0]) and not checkprime(lst[0])):
return False
length = len(lst)
if length == 1:
return True
if checksquare(lst[0]):
# if first element is square then make s(quare)=2 and p(rime)=1
s, p = 2, 1
else:
# if first element is prime then make s=1 and p=2
s, p = 1, 2
# running perfect square loop from s to len-1 with gap of 2 and checking condition
for i in range(s, length, 2):
if not checksquare(lst[i]):
return False
# running prime loop from p to len-1 with gap of 2
for i in range(p, length, 2):
if not checkprime(lst[i]):
return False
return True
def checksquare(n): # function to check perfect square
if n < 0:
return False
if 0 <= n <= 1:
return True
for i in range(int(n ** 0.5) + 1):
if i * i == n:
return True
return False
def checkprime(n): # function to check prime
if n < 2:
return False
if n % 2 == 0:
return n == 2
for i in range(3, int(n ** 0.5) + 1, 2):
if n % i == 0:
return False
return True

Categories