ValueError in python. - python

Here is my code:
def f(x): return x%2!=0 and x%3!=0
primes = filter(f , range (6,50))
for x in primes:
for a in filter(f, range(2,x-1)):
if x%a == 0:
primes.remove(x);
print(primes)
I get this error:
File "primes.py", line 12, in <module>
primes.remove(x);
ValueError: list.remove(x): x not in list
But the funny thing is if i write like that:
def f(x): return x%2!=0 and x%3
primes = filter(f , range (6,20))
for x in primes:
for a in filter(f, range(2,x-1)):
if x%a == 0:
primes.remove(x);
print(primes)
Why? and how can i fix it?

Let's put in some print statements to see what's going on:
In [81]: %paste
def f(x): return x%2!=0 and x%3!=0
primes = filter(f , range (6,50))
print primes
for x in primes:
for a in filter(f, range(2,x-1)):
if x%a == 0:
print x
primes.remove(x);
print(primes)
## -- End pasted text --
[7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49]
25
35
35
So your problem is that you're producing the number 35 twice (and you get an exception the second time because it's not there after you remove it the first time!)

Let's look at the result:
>>> primes = filter(f , range (6,50))
>>> primes
[7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49]
You have the value 35 here, which is 5*7. In your nested loop, when a is 5, the condition is met and 35 is removed from the list of primes; when a goes to 7, the condition is met again, but this time 35 is already removed, so a exception is raised.
So a simple fixed is like the one below. such that x is removed only once when the condition is first met:
for x in primes:
for a in filter(f, range(2,x-1)):
if x%a == 0:
primes.remove(x)
break
But now it will skip the element right after a non-prime number, such as 95 in this list:
primes=[7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49, 53, 55, 59, 61, 65, 67, 71, 73, 77, 79, 83, 85, 89, 91, 95, 97]
which is fixed by making a slice of primes:
for x in primes[:]:
for a in filter(f, range(2,x-1)):
if x%a == 0:
primes.remove(x)
break

Related

Collatz Conjecture Sequence iterations and multiple divisor

For the case, the sequence does not end in 1. How can I create a code that has some way of stopping the execution if 1 is not reached after a certain number of iterations? I just don't know how to add this to my code below. And is there a way to make it work with a list of divisors such as [2, 3]? I'm using Python.
import numpy
#change the function to have 3 input args, the number, the multiplier and the
divisor
def collatz(n,multiplier,divisor):
list1 = [n]
if n == 1 :
return [1]
elif n % 2 and n % 3 == 0 :
#edit the function's input args for both the else and elif loops
list1.extend(collatz(n//divisor,multiplier,divisor))
else:
list1.extend(collatz(n*multiplier+1,multiplier,divisor))
return list1
#driver function to get the input number, multiplier and divisor
if __name__=="__main__":
n=int(input("Enter any positive integer N: "))
multiplier=int(input("Enter the multiplier: "))
divisor=int(input("Enter the divisor: "))
print("\n",collatz(n,multiplier,divisor))
You will get a stack overflow error after ~1000 recursions I believe.The way to override this: https://stackoverflow.com/a/3323013/10875953. But 2^64 is immensly large, you won't be able to do that. Rather try making a iterative function.
You should use your divisor parameter in the condition that select the operation on the number.
To make this easier to manage, you shouldn't use recursion. A simple while loop will suffice:
def collatz(n,divs=2,mult=3,inc=1,maxSize=-1):
result = []
while n not in result and len(result)!=maxSize:
result.append(n)
n = (n*mult+inc)if n%divs else n//divs
return result + ['...']*(n not in result)
output:
print(collatz(20))
[20, 10, 5, 16, 8, 4, 2, 1]
print(collatz(30,2,6,2,maxSize=10))
[30, 15, 92, 46, 23, 140, 70, 35, 212, 106, '...']
print(collatz(30,2,6,2))
[30, 15, 92, 46, 23, 140, 70, 35, 212, 106, 53, 320, 160, 80,
40, 20, 10, 5, 32, 16, 8, 4, 2, 1]
print(collatz(30,2,5,3))
[30, 15, 78, 39, 198, 99, 498, 249, 1248, 624, 312, 156]
print(collatz(60,4,3,-2,maxSize=10))
[60, 15, 43, 127, 379, 1135, 3403, 10207, 30619, 91855, '...']

find second duplicate and period in a python list

I've a python list as this one [2, 5, 26, 37, 45, 12, 23, 37, 45, 12, 23, 37, 45, 12, 23, 37]. The real list is really long. The list repeat itself after a certain point in this case after 37. I have no problem finding the number at which it repeats, but i need to truncate the list at the second one. In this case the result would be [2, 5, 26, 37, 45, 12, 23, 37]. For finding the number (37 in this case) i use a function firstDuplicate() found on stackoverflow. Someone can help me ?
def firstDuplicate(a):
aset = set()
for i in a:
if i in aset:
return i
else:
aset.add(i)
pass
pass
pass
LIST = LIST[1:firstDuplicate(LIST)]
You can use the same basic idea of firstDuplicate() and create a generator that yields values until the dupe is found. Then pass it to list(), a loop, etc.
l = [2, 5, 26, 37, 45, 12, 23, 37, 45, 12, 23, 37, 45, 12, 23, 37]
def partitionAtDupe(l):
seen = set()
for n in l:
yield n
if n in seen:
break
seen.add(n)
list(partitionAtDupe(l))
# [2, 5, 26, 37, 45, 12, 23, 37]
It's not clear what should happen if there are no dupes. The code above will yield the whole list in that case.
A function to find the period size and length of repeated numbers should start from the end of the sequence of numbers. This will make it easier to ensure that there is a cycle up to the end of the list and avoid any concerns over non-periodic repetitions at the beginning of the list.
For example:
def getPeriod(seq):
lastPos = { n:p for p,n in enumerate(seq) }
prevPos = { n:p for p,n in enumerate(seq) if p<lastPos[n] }
period = 1
for n in reversed(seq):
if n not in prevPos: break
delta = lastPos[n] - prevPos[n]
if delta%period == 0 or period%delta == 0:
period = max(delta,period)
else: break
nonPeriodic = (i for i,(n,p) in enumerate(zip(seq[::-1],seq[-period-1::-1])) if n != p)
periodLength = next(nonPeriodic,0)
return period, periodLength
output:
seq = [2, 5, 26, 37, 45, 12, 23, 37, 45, 12, 23, 37, 45, 12, 23, 37]
period, periodLength = getPeriod(seq)
print(period,periodLength) # 4 9
print(seq[:-periodLength]) # [2, 5, 26, 37, 45, 12, 23]

Python function that generates random arrays of integers not working

I need to create a function that generates random arrays of integers between a and b, inclusive, where a and b define the range and M and N define the size of the output array. I've done something but it seems that it's not properly working and I don't know exactly how can I define the size of the output array, where exactly to put M and N.....Here it's my code:
import random
def Rand(start, end, num):
res = []
for j in range(num):
res.append(random.randint(start, end))
return res
# Driver Code
num = 10
start = 20
end = 40
print(Rand(start, end, num))
You just need two nested loops (or a nested list comprehension)
For example:
import random
def random_array(start, end, a, b):
return [[random.randint(start, end) for _ in range(a)] for _ in range(b)]
# Driver Code
a = 10
b = 5
start = 20
end = 40
print(random_array(start, end, a, b))
Which, in my case, output:
[[35, 27, 30, 27, 26, 37, 38, 27, 36, 34], [24, 24, 29, 35, 27, 38, 38, 37, 24, 24], [35, 20, 38, 25, 26, 20, 31, 29, 27, 33], [37, 36, 34, 20, 27, 30, 33, 26, 24, 26], [28, 35, 20, 31, 33, 36, 29, 25, 36, 36]]
If you don't want to use list comprehensions (although you probably should), it would be the equivalent of:
def random_array(start, end, a, b):
res = []
for _ in range(b):
inner = []
for _ in range(a):
inner.append(random.randint(start, end))
res.append(inner)
return res
Final note: According to PEP-8 you shouldn't start a function name with a capital letter.

for loop based on dynamic list python

Edit:
The desired behaviour of the program is to find the number sequences that have an increasing trend, so I want to generate from ks list a list like this:
desiredList=[[97,122],[98,111],[98,101,103,103,104]]
I have the following, my goal is to run the for loop based on the length of the list, the list length gets changed inside the for loop itself. Python takes into account only the length before the for loop, when the length of the list is changed in the loop it still takes the older value before the loop. Here is the code:
ks=[97,122,111,98,111,98,101,103,103,104,97]
splitLine=2
counter=[]
for i in range(0,len(ks)):
a=ks[i:splitLine]
while len(a)>1:
for j in range(0,len(a)):
m=j
n=j+1
if(a[m]-a[n]<=0):
c=c+1
k=splitLine+c-1
a.append(ks[k]) #When append happens, the for loop still takes the older value of len(a) instead of new value
else:
a.pop(-1)
counter.append(a)
splitLine=splitLine+1
a=[]
break
A quick fix for your looping problem would be to swap out your for loop for a while loop. Change this:
for j in range(0,len(a)):
# <loop contents>
to this:
j = 0
while j < len(a):
# <loop contents>
j += 1
The for loop is grabbing values of j out of a range (a list in Python 2, and a generator object in Python 3). This range is calculated when the for loop is run the first time; it will not update after that, no matter what you do to a.
The while loop gives you more control in this situation, because you can specify the condition under which you want to exit the loop.
Your implementation is probably nesting too many loops for the problem it is trying to solve.
This first implementation contains an error. See below for the fix.
Try something along these lines perhaps:
l = [97,122,111,98,111,98,101,103,103,104,97]
out = []
acc = []
for v in l:
if len(acc)==0 or v >= acc[-1]:
acc.append(v)
else:
if len(acc) > 1:
out.append(acc)
acc = [v]
print(out)
>>>[[97, 122], [98, 111], [98, 101, 103, 103, 104]]
That previous code is slow and can drop the last found fragment. I found that error while running random tests on it to try an optimized version. The following code shows the original code with the correction and the optimized version which can be 30% faster.
def original(l):
out = []
acc = []
added = False
for v in l:
if len(acc)==0 or v >= acc[-1]:
acc.append(v)
else:
added = False
acc = [v]
if acc is not None and len(acc)>1 and not added:
added = True
out.append(acc)
return out
def optimized(l):
out = []
acc = None
tmp = None
deb_v = False
for v in l:
prev = acc[-1] if (acc is not None and len(acc)) else tmp
if prev is not None and v >= prev:
if tmp is not None:
acc = []
acc.append(tmp)
out.append(acc)
tmp = None
acc.append(v)
else:
acc = None
tmp = v
return out
# The original test data
l = [97,122,111,98,111,98,101,103,103,104,97]
assert original(l) == optimized(l) == [[97,122],[98,111],[98,101,103,103,104]]
# A list that triggered last-fragment-dropped error
l = [57, 16, 6, 19, 40, 3, 4, 13, 2, 70, 85, 65, 32, 69, 54, 51, 95, 74, 92, 46, 45, 26, 0, 61, 99, 43, 67, 71, 97, 10, 18, 73, 88, 47, 33, 82, 25, 75, 93, 80, 23, 37, 87, 90, 49, 15, 35, 63, 17, 64, 5, 72, 89, 21, 50, 8, 41, 86, 31, 78, 52, 76, 56, 42, 77, 36, 11, 60, 39, 22, 68, 27, 24, 28, 59, 96, 29, 38, 12, 79, 53, 9, 83, 94, 34, 14, 7, 48, 30, 20, 66, 62, 91, 58, 81, 1, 98, 44, 55, 84]
assert original(l) == optimized(l)
# Random testing
import random
l = list(range(100))
random.shuffle(l)
assert original(l) == optimized(l)
# Timing!
import timeit
print(timeit.timeit("original(l)", globals={"l":l, "original": original}))
# 43.95869998800117
print(timeit.timeit("optimized(l)", globals={"l":l, "optimized": optimized}))
# 34.82134292599949
As Moinuddin says, the root of your problem isn't clear to us. However, the code below shows how you can keep iterating over a list as its length changes:
def iterate_for_static_list_length(l):
for i in range(len(l)):
yield i
l.append(object())
def iterate_for_dynamic_list_length(l):
for i, _ in enumerate(l):
yield i
l.append(object())
if __name__ == '__main__':
l = [object()] * 3
print('Static implementation')
for value in iterate_for_static_list_length(l):
input(value)
print('\nDynamic implementation')
for value in iterate_for_dynamic_list_length(l):
input(value)
Output
Static implementation
0
1
2
Dynamic implementation
0
1
2
3
4
5
6
7
8
This program will keep going forever. In your code I can see that you conditionally append to the list within the loop, so it seems like it should terminate eventually.

Infinite Recursion in Python Function if Argument Too Long

I wrote this recursive function that returns the largest value in a list of integers:
def max_r(l: [int]) -> int:
if len(l) == 1:
return l[0]
else:
return l[0] if max_r(l[1:]) < l[0] else max_r(l[1:])
The call max_r([1,4,3,2,3,4,89,2,30,1] returns 89, but calling the function on a longer list:
max_r([96, 84, 87, 81, 94, 74, 65, 42, 45, 76, 5, 37, 86, 8, 46, 54, 62, 63, 35, 85, 16, 23, 18, 57, 51, 90, 58, 33, 47, 10, 64, 49, 67, 29, 71, 30, 9, 99, 75, 3, 97, 32, 59, 25, 27, 72, 61])
results in infinite recursion. Why?
It isn't infinitely recursive, but you are doing the same recursive call twice when you don't need to. Seems to complete quickly enough with the following change:
def max_r(l: [int]) -> int:
if len(l) == 1:
return l[0]
else:
result = max_r(l[1:])
return l[0] if result < l[0] else result
This isn't just a matter of calling the function recursively twice as many times, I'm not sure on the exact growth rate but it seems be exponential since each extra recursive call will be making more extra recursive calls.

Categories