Reputation: 434
I would like to iterate over a set while I'm deleting items from it. There are similar questions for deleting one item at the time or for lists, but they do not work for my case.
The code follows; I iterate over a
set ZN
and in the end of the iteration I'm removing a
few items (the ones belonging to the set temp
). But the
iteration is still happening over the "original" ZN.
How can I modify this code to change the set ZN while I'm iterating over it?
def CyclotomicCosets(q,n):
N=q^n-1
ZN=set(range(N))
Cosets=[]
for i in ZN:
tmp=set([])
for j in range(n):
tmp.add( i*(q^j) %N)
Cosets.append(list(tmp))
ZN=ZN.difference(tmp) # <------------ Does not do what I want
return(Cosets)
Upvotes: 2
Views: 11330
Reputation: 1123400
Use a while
loop and .pop()
values to process from the set:
def CyclotomicCosets(q, n):
N = q ^ n - 1
ZN = set(range(N))
Cosets = []
while ZN:
i = ZN.pop()
tmp = {i * (q ^ j) % N for j in range(n)}
Cosets.append(list(tmp))
ZN -= tmp
return Cosets
Note that I replaced your inner for
loop with a set comprehension to make it a little faster and more compact. These were introduced in Python 2.7 and Python 3, in earlier versions of python you can use a generator expression instead:
tmp = set(i * (q ^ j) % N for j in range(n))
Your original mistake was to replace ZN
rather than update it:
ZN=ZN.difference(tmp)
This did not alter the original set you were using in the for
loop. Rather, you are creating a new set and point the ZN
reference to that.
However, you cannot modify a set
while iterating over it, so even an in-place difference would not have worked; you would have to use ZN -= tmp
or ZN.difference_update(tmp)
but that would lead to exceptions instead:
>>> ZN = set(range(3))
>>> for i in ZN:
... ZN -= set([2])
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: Set changed size during iteration
The corrected code gives:
>>> CyclotomicCosets(3, 5)
[[0], [0, 1, 2, 3], [0, 1, 4, 5], [0, 4, 5, 6]]
Alternatively, loop over range(N)
instead, and keep a set of values you've already processed:
def CyclotomicCosets(q, n):
N = q ^ n - 1
Cosets = []
seen = set()
for i in range(N):
if i in seen: continue
tmp = {i * (q ^ j) % N for j in range(n)}
Cosets.append(list(tmp))
seen |= tmp
return Cosets
Upvotes: 1