1

Is there a way to keep the length of a list constant while continuously appending to it during iteration?

I tried deque, but it gives me a runtime error and I read it's not possible to leftpop elements.

I tried it with list.pop(0) and list.append() but the indexes get messed up.

The deque methode would be perfect, specifying a maxlength and then just having a 'rolling window' where slice_items get added if needed for a later do-over, and items at the beginning get popped to not run out of memory. Basically it can run forever until the work is done, no new elements get added back, and the list is depleted

for symbol in symbols:
        slices = ['year1month1', 'year1month2', 'year1month3', 'year1month4']
        for slice_item in slices:
               # do something here

               if something didnt work:
                   slices.pop(0)
                   slices.append(slice) 
                   ...       

here my approach with the runtime error:

for symbol in symbols:
        slices = deque(['year1month1', 'year1month2', 'year1month3', 'year1month4'],maxlen=24)
        for slice_item in slices:
               # do something here

               if something didnt work:
                   slices.append(slice) 
                   ...       

Update, thanks to @Buran; for completeness:

from collections import deque

symbols = ('a','b','...','n')
slices = ('year1month1', 'year1month2', 'year1month3')

for symbol in symbols:
    slice_queue = deque(range(len(slices)))  
    while slice_queue:
        slice_idx = slice_queue[0]           
        # do something
        done = symbols + slices[slice_idx]
        if done:
            slice_queue.popleft()
        else:
            slice_queue.rotate(-1)

chubaka
  • 51
  • 8
  • 1
    What is the problem with the `deque` you mention in your question? Look at [collections.deque](https://docs.python.org/3/library/collections.html#collections.deque) – buran Oct 29 '21 at 18:11
  • According to https://www.geeksforgeeks.org/deque-in-python/ you can use `popleft()` on `deque`s – Einliterflasche Oct 29 '21 at 18:12
  • 1
    @Einliterflasche, no need, they can set `maxlen` – buran Oct 29 '21 at 18:13
  • the problem is, when i leftpop on deque i get : RuntimeError: deque mutated during iteration – chubaka Oct 29 '21 at 18:14
  • 2
    It's worth to mention you should not change list while iterating over it. Have a look at https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating – buran Oct 29 '21 at 18:20
  • thank you @buran, works like a charm, but in a nested loop like above e.g. ````for n in m: while deq````. when the inner loop finishes it also breaks out of the ````for```` loop – chubaka Oct 30 '21 at 04:44
  • Sorry, I don't understand what you mean. Can you provide [mre] as well as expected output. This starts to look very much like XY problem. – buran Oct 30 '21 at 05:44
  • own mistake, i didnt add a new queue before the start of a 2nd for loop ````for n in m: deq = deque(range(5)) while deq:```` question is solved , thanks alot for pointing me the right way – chubaka Oct 30 '21 at 07:06

1 Answers1

3

EDIT: After reading your question again, I think I get it wrong, but I will keep my original answer anyway, see at the end.

Have a look at collections.deque. I think you need to rotate the deque, not maxlen. This way you create a queue, sending failed tasks at the end.

from collections import deque
from random import choice

success = [True, False]

deq = deque(range(5))
while deq:
    if choice(success): # for the example randomly choose result of operation
        num = deq.popleft()
        print(f'Success: {num}')
    else:
        print(f'Fail: {deq[0]}')
        deq.rotate(-1) # rotate the deque to left
        print(deq)

sample output:

Fail: 0
deque([1, 2, 3, 4, 0])
Fail: 1
deque([2, 3, 4, 0, 1])
Fail: 2
deque([3, 4, 0, 1, 2])
Fail: 3
deque([4, 0, 1, 2, 3])
Success: 4
Fail: 0
deque([1, 2, 3, 0])
Success: 1
Success: 2
Fail: 3
deque([0, 3])
Fail: 0
deque([3, 0])
Success: 3
Success: 0

My original answer:

Have a look at collections.deque and set maxlen

From the docs:

If maxlen is not specified or is None, deques may grow to an arbitrary length. Otherwise, the deque is bounded to the specified maximum length. Once a bounded length deque is full, when new items are added, a corresponding number of items are discarded from the opposite end. Bounded length deques provide functionality similar to the tail filter in Unix. They are also useful for tracking transactions and other pools of data where only the most recent activity is of interest.

example

from collections import deque

deq = deque(maxlen=3)

for num in range(10):
    deq.append(num)

print(deq)

output

deque([7, 8, 9], maxlen=3)
buran
  • 13,682
  • 10
  • 36
  • 61