This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 1 year ago.
I'm new with python language and I'm having trouble to understand why this code doesn't work as I expect.
I want to calculate and put in a tuple the primitive pythagorean triplet (a^2+b^2=c^2) for a,b,c < 100.
This is the code
n=100
#Here I calculate all the pythagorean triples and I put it in a list(I wanted to use the nested list comprehension)
d=[(ap,b,c) for ap in range(1,n+1) for b in range(ap,n+1) for c in range(b,n+1) if ap**2 + b**2 == c**2 ]
#it work
#now I wonna find the primitive one:
q=[]
for q in d: #I take each triples
#I check if it is primitive
v=2
for v in range(2,q[0]) :
if q[0]%v==0 and q[1]%v==0 and q[2]%v== 0 :
d.remove(q) #if not I remove it and exit from this cycle
break
#then I would expect that it read all the triples, but it doesn't
#it miss the triples after the one I have cancelled
Can you tell me why?
Is there another way to solve it?
Do I miss some step ?
The missing 3-tuples are not caused by the break but by modifying a list at the same time that you loop it. When you remove an element from a list, the remaining element's indexes is also modified, which can produce a loop to skip certain elements from being checked. It's never a good practice to remove elements from a list you are iterating. One usually create a copy of the list that you iterate, or use functions such as filter.
Also, you can remove v = 2. There's no need to set the value of v to 2 for every iteration when you already do so with the instruction for v in range(2,q[0])
Iterating over a copy of d
If you do list(d) then you create a clone of the list you are iterating. The original list can be modified but it won't be a problem because your loop will always iterate over the original list.
n=100
d=[(ap,b,c) for ap in range(1,n+1) for b in range(ap,n+1) for c in range(b,n+1) if ap**2 + b**2 == c**2]
q=[]
for q in list(d):
for v in range(2,q[0]) :
if q[0]%v==0 and q[1]%v==0 and q[2]%v== 0 :
d.remove(q)
break
Use the function filter
For the filter function , you need to define a function that is applied to every element of your list. The filter function uses that defined function to build a new list with the elements that pass. If the defined function returns True then that element is kept and used for the new list, if it returns False, then that element is not used. filter() returns an iterator, so you need to build the list from it.
def removePrimitives(q):
for v in range(2, q[0]):
if q[0] % v == 0 and q[1] % v == 0 and q[2] % v == 0:
return False
return True
n=100
d=[(ap,b,c) for ap in range(1,n+1) for b in range(ap,n+1) for c in range(b,n+1) if ap**2 + b**2 == c**2]
q=[]
d = list(filter(removePrimitives, d))
Bonus: debugging
When it comes to coding, no matter what language, I believe one of the first things you should learn to do is how to debug it. Python has an amazing interactive debugging module called: ipdb.
Here's the commands:
n[ext]: next line, step over
s[tep]: step into next line or function.
c[ontinue]: continue
l[ine]: show more lines
p <variable>: print value
q[uit]: quit debugging
help: show all commands
help <command>: show help
Install the package with your pip installer. Here's how you could have used it in your code to see exactly what happens when a primitive tuple is found and you break from the inner loop:
import ipdb
n=100
d=[(ap,b,c) for ap in range(1,n+1) for b in range(ap,n+1) for c in range(b,n+1) if ap**2 + b**2 == c**2 ]
q=[]
for q in d:
for v in range(2,q[0]) :
if q[0]%v==0 and q[1]%v==0 and q[2]%v== 0 :
ipdb.set_trace() # This sets the breakpoint
d.remove(q)
break
At this breakpoint you can print the variable q, and d, and see how it gets modified and what happens after the break is executed.
Related
This question already has answers here:
Can anyone explain me Python for loop (or iteration) algorithm
(4 answers)
Closed 2 years ago.
In the below, I have several questions. Firstly, why do we not define the starting value of i? In WHILE loops I came across this was the case. Secondly, I am finding it difficult to understand the "sequence" of what is happening. I understand that m = L[0] = 1 but the subsequent steps are not clear to me.
L=[1,2,4,-5,7,9,3,2]
m = L[0]
for i in L:
if i<m:
m = i
print(m)
For loops in python are really "for each" loops. Read it as "for each value 'i' in list 'L', do...".
i is not an index, it is the actual element in the list L.
So we set the initial minimum to just the first element of the list, and we say, for each element in our list, if there is a value smaller than our current minimum, we'll set our minimum to that element.
You don't want to define the starting value of i to make the program more variable to other cases. M is going to be the lowest value because that is what we are printing out. So if i is lower than m we want i to be m. The for loop goes through every number in the list.
L=[1,2,4,-5,7,9,3,2]
m = L[0] # start with m as the first value of your list which is 1.
for i in L: # for i in L means for i being consecutively 1 then 2 then 4 then -5 etc...
if i<m: # if i is less than m the starting point, give the value of i to m
# example if m = 1 and i =-3 after this condition m will take the value -3
m = i
print(m) # when you finish looping over all the examples print my m value
I would suggest writing the algorithm on a paper and you will see how easy it is.
m=1
loop
i=1
i<1? No.
go back to loop
i=2
i<1? No.
go back to loop
i=4
i<1? No.
go back to loop
i=-5
i<1? YES.
m = -5
go back to loop
.
.
.
The for loop proceeds via a form of hypothesis testing. First, we establish a loop invariant: something that remains true before and after each iteration. In this case, it is that m is the smallest value in the list that we have seen so far.
When we initialize m = L[0], it is true: having looked only at L[0], m is the smallest value we've seen so far.
Inside the loop, i takes on each value in the list exactly once. We compare it to m, and if i is indeed smaller, we use it as the new value of m. So after each iteration, m remains the smallest value seen so far.
Once the loop completes, having set i to each element in turn, we can conclude that m is not only the smallest value in L that we've seen so far, but it is the smallest value in L, period, because we have looked at every value in L.
The for loop is equivalent to the following while loop:
_index = 0
while True:
try:
i = L[_index]
except IndexError:
break
if i < m:
m = i
_index += 1
As you can see, we initialize _index to 0, and increment it explicitly at the end of each iteration. The for loop essentially keeps track of _index for us. i, on the other hand, is not initialized so much as it is derived from the current values of L and _index.
More generally, for loops don't manage repeated indexing operations, but are based on the iterator protocol. A for loop like
for i in L:
...
is roughly equivalent to
_itr = iter(L)
while True:
try:
i = next(_itr)
except StopIteration:
break
...
There is an easier way to do it without using a for loop so you can run your whatever code you want to run using the min() function for example in here:
L=[1,2,4,-5,7,9,3,2]
print(min(L)
I would recommend using something like this because its easier faster and runs smoother than the code in your question. The code in your question first runs a for loop that gets all the values out of the list and store them as i and runs threw them then it goes to the if statement which checks if the value which is i in this example is smaller than m which has the value of 1 then rewrites the variable m which was the value 1 to the value that is smaller than i which is -5 and as you see there this is a lot of function to run throw and that makes your code slower if the code consist of many lines.(Tip: always try using as minimum for loops or if statements as you can.)
your example:
L=[1,2,4,-5,7,9,3,2]
m = L[0]
for i in L:
if i<m:
m = i
print(m)
My apology for this most inane question. I have very basic python knowledge, and I'm working on it. I need to create a simply list in python that would take a function call with two arguments createList(v,n):
So that value would be a string say e and the next argument would be a number 5 and that would then create a list-
['e','e','e','e','e','e']
Conceptually I understand that e would be at index 0 and 5 would be at index 1, but I have no idea how to actually use the arguments to make the list.
I have searched to try and learn but there is nothing so simply as this. Again, my apology for the inane question, but I am trying!
def createList(v,n):
return [v] * n
You use the arguments by simply referring to them by name :) . No need to worry about which argument is first or second when you are inside createList — though they do need to be in the right order when you call createList.
[v] makes a one-element list that contains v.
* n, when applied to lists, expands that list to include n copies of what it had before.
return returns the value from the function.
def createList(v,n):
return [v for i in range(n)]
This solution is based on list comprehension.
def createList(v,n):
print([v for i in range(n)])
You can learn function and arguments in
https://www.tutorialspoint.com/python/python_functions.htm
Slight improved answered of #cxw. Which will work for almost all the case except when n = 0.
def createList(v,n):
return [v] * n if (n != 0) else [v]
Since if n=0 the list [v] * 0 would become empty [] list which I think wont be expected result in your case.
I have a boolean array in python and I want to do a calculation on the cells where the value is 'true'. Currently I am using a nested for loop to go trough all the cells to find the cells with the true values. However, running the program takes a lot of time. I was wondering wether there is a faster way to do this?
for i in range (0,latstep):
for j in range (0,lonstep):
if coastline[i,j] == True:
...
Thanks for your help!
You might consider using concurrent.map() or similar to process the array elements in parallel. Always assuming there aren't dependencies between
the elements.
Another possibility is maintaining a list of the 'true' values when you initially calculate them:
coastlineCache = []
c = foo()
coastline[i][j] = c
if (c):
coastlineCache.append(c)
// later
for (c in coastlineCache):
process_true_item(c)
If, as you've alluded to above, you need the array indices, cache them as a tuple:
coastlineCache = []
c = foo()
coastline[i][j] = c
if (c):
coastlineCache.append((i, j))
// later
for (c in coastlineCache):
process_true_item(c[0], c[1]) # e.g. (i, j)
You can use nested list comprehensions, each comprehension is slightly faster than a generic for-loop on smaller input sizes:
final_list = [[foo(b) for b in i if b] for i in coastline]
I currently have this piece of code (for squares), but it doesn't seem to be working correctly:
for n in range(len(dict)):
if n == 0:
pass
else:
squares = (n*n)
dict[n]=squares
The parameter of range() should be n, because the dictionary is probably empty when you begin.
Also, dict is a builtin type in python and you shouldn't name your variables this way.
squares = {i:i*i for i in xrange(n)}
dict={}
for i in range(n):
dict[i]=i*i
squares={}
for r in range(int(n) + 1):
if r == 0:
pass;
else:
squares[r] = (r * r)
This code will create a dictionary, look through all of the values up to n, and add the square tot he dictionary at index "r"! This code fulfills all of the requirements you asked for! Let me know if you have any questions!
It's not clear from the question whether dict already contains values. Also I'm not sure why you're skipping n==0.
Assuming you have a list dict with a certain length, your code should work for all values except the first (which you're skipping), except that your last line is not indented, so it's not run inside the loop. This should do it:
for n in range(len(dict)):
dict[n]=n*n
Anyway I recommend a list comprehension to do this:
dict = [n*n for n in len(dict)]
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
calling func. change the input
I have to write a recursive function that takes a list of numbers in input and returns a list of numbers in output, for example called like this:
rec_cumsum([2,2,2,3])
the output should be like:
[2,4,6,9]
Thing is, I cant seem to get my head around for this to work.. this got me questioning my whole recursive thinking..
what i have so far is :
newlist = []
k = 1
def rec_cumsum(numbers):
if len(numbers) == 0:
return 0
if len(numbers) > 1 and len(numbers) != (k+1):
newlist[k+1] == newlist[k+1] + newlist[k]
k = k+1
return rec_cumsum(numbers)
but I'm getting errors which doesn't really make any sense to me.
the recursion should always take the number, and add it to the one before it, than save it in the next location of the list.. (new one or original one)
I would write it like this:
def cumulative_sum(lst,prev=0):
if not lst:
return []
else:
elem = prev+lst[0]
return [elem] + cumulative_sum(lst[1:],prev=elem)
print cumulative_sum([2,2,2,3])
Now to look at your code (note I didn't actually work through the logic to decide whether it would give the correct result, the following only addresses possible exceptions that your code is probably throwing):
You're probably getting an IndexError because of this line:
newlist[k+1] == newlist[k+1] + newlist[k]
You're assigning to a list position which doesn't exist yet. You could pre-allocate your list:
newlist = [0]*len(lst)
but even if you fix that, you'll get a recursion error with your code because of the line:
k = k + 1
The problem here is that on the left hand side, k is local whereas on the right hand side, k is global. So essentially each time you run this, you're getting the local k == 2 and not touching the global one. If you really want to modify the global k, you need to declare k as global via global k. Of course, then you need to reset k every time you're going to use this function which would be a somewhat strange API.