0

I've been trying to figure out why I lose the second item in my list each time I iterate through it.

def main():
    _data = [0,1,3,0,5,5]
    print(_data)
    # Convert items in the list into strings
    for item in _data:
        item = str(item)
        print(item)
        _data.append(item)
        _data.pop(0)
    print(_data)
main()
  • 3
    `_data.pop(0)` won't update the `for item in _data:` iterator position, which advances from `index` to `index + 1` each step. `_data.pop(0)` means all remaining elements have shifted position from `index` to `index - 1`, so effectively what was at `index + 1` before is now at `index` and is skipped. Don't iterate and delete at the same time! – Martijn Pieters Mar 15 '19 at 11:17
  • 1
    what exactly are you trying to do – Jeril Mar 15 '19 at 11:18
  • Fwiw, you can get the result you want (convert items to strings) with `_data = list(map(str, _data))`, or if you prefer list comprehensions `_data = [str(item) for item in _data]`. Both of these actually create a new list instead of editing the existing one in place, but that is most times the best practice for these cases (you could also iterate index values and change elements in place, but it's usually less idiomatic). – jdehesa Mar 15 '19 at 11:19
  • Editing list which is already iterated is really bad idea. You will mess with `index`. – Karls Mar 15 '19 at 11:19
  • 1
    Not that you need to delete anything. If you want to update `_data` in place, use `_data[:] = [str(item) for item in _data]`, or just assign to the index with `for i, item in enumerate(_data): _data[i] = str(item)`. – Martijn Pieters Mar 15 '19 at 11:20
  • @MartijnPieters That's interesting, is Python actually able to optimize that (I mean CPython, I guess)? Or does it just create a new list anyway and then copies to the other one? – jdehesa Mar 15 '19 at 11:22
  • 1
    @jdehesa: it can't be optimised, a new list is created. The slice assignment does then know not to just empty the current list, but to copy across the references (it has a new list to reference and compare item count with). – Martijn Pieters Mar 15 '19 at 11:27
  • Would like to thank everyone for the solutions they provided, it seems there's certainly a number of ways to do this MUCH better than I was attempting. – Virgil Jones Mar 15 '19 at 23:19

1 Answers1

1

The best you can expect when changing an object you're iterating over is unexpected behaviour.

Create a second, empty list and add the elements converted as strings from the first list to the second, in order to avoid this.

jfaccioni
  • 7,099
  • 1
  • 9
  • 25
  • They don't need to create a second list *at all*, because they don't need to delete anything. They are simply replacing all items with their `str()` conversion, in a very inefficient manner (quadratic time, doubling the list length takes 4 times as long to process). – Martijn Pieters Mar 15 '19 at 11:26