1

input:

ls = ['hi', 'bye', 'cya', 'hello', 'nope']
ls_popped = []


i = 0
while i < 3:
    ls_popped.append(ls.pop(i))
    i += 1

print(ls)
print(ls_popped)

output:

['bye', 'hello']
['hi', 'bye', 'nope']

expected output:

['hello', 'nope']
['hi', 'bye', 'cya']

i believe the pop function pops and returns the element at index i, so it should pop from i = 0 to 2 and return these elements to the new list. im not sure why this is not working as expected.

Mr Habibbi
  • 31
  • 4
  • 4
    After you pop the element at index 0, *the indexes of all other elements change*. When you then pop index 1, that's the element that was originally at index 2, and so on. – jasonharper Jun 17 '22 at 13:50
  • This is a duplicate of iterating array while removing elements – Kavindu Ravishka Jun 17 '22 at 14:04
  • @KavinduRavishka If you're talking about [this question](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating), that one is focused on the problems with `iter`-style iterators and for-each, which does cause big problems when removing elements. A `while` loop like OP is doing is perfectly safe; they just have to take care with the indices. One is a theoretical limitation with Python's `iter` interface, the other simply requires a bit of care on the part of the programmer. – Silvio Mayolo Jun 17 '22 at 14:07
  • @SilvioMayolo There is no difference between these two since in this code i is increased every time. Has the same effect as iter – Kavindu Ravishka Jun 17 '22 at 14:10
  • @SilvioMayolo only differece is this wont throw an index error – Kavindu Ravishka Jun 17 '22 at 14:12

3 Answers3

2

Let's trace it through. At the beginning of your program, we have

ls = ['hi', 'bye', 'cya', 'hello', 'nope']
ls_popped = []
i = 0

Now we run the loop once. We pop the element at position 0 and append it to ls_popped.

ls = ['bye', 'cya', 'hello', 'nope']
ls_popped = ['hi']
i = 1

Great! Now the loop variable is 1. So we pop the thing at position 1. Note that that's not bye: bye is at 0 now, while cya is at 1.

ls = ['bye', 'hello', 'nope']
ls_popped = ['hi', 'cya']
i = 2

Now i is 2, so we're looking at position 2, which contains nope.

ls = ['bye', 'hello']
ls_popped = ['hi', 'cya', 'nope']
i = 3

Now i is 3 so the loop exits and we move on, printing the result

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
2

It helps to see your list visually:

'hi', 'bye', 'cya', 'hello', 'nope'
-----------------------------------
 0       1      2       3       4

We start with the while loop at 0, and extract the first element and put in ls_popped. When you extract the first element the remaining elements in ls shift, so visually it will look like:

'bye', 'cya', 'hello', 'nope'
-----------------------------
 0       1      2       3

Now i is increased to 1 and so you now extract cya and append it in the ls_popped.

ls:

'bye', 'hello', 'nope'
----------------------
 0       1        2       

Now i is 2, we so we extract nope and append it to ls_popped.

0

A better way to break the list in parts is through slicing, not through a loop and pop:

ls = ['hi', 'bye', 'cya', 'hello', 'nope']
idx_cut = 3
ls_popped = ls[:idx_cut]
ls = ls[idx_cut:]
print(ls)
print(ls_popped)
# ['hello', 'nope']
# ['hi', 'bye', 'cya']

SEE ALSO:

Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47