Python idiom for iterating over changing a list
Is there a better (more obvious / idiomatic) way in python to write an equivalent
index = 0
while index < len(some_list):
do_some_stuff(some_list[index]) # may have many side effects
if delete_element(some_list[index]):
del some_list[index]
else:
index += 1
or a dictionary equivalent to this dictionary for dictionaries? Dict / list comprehension is not a thing, because the result delete_element
can depend on do_some_stuff
.
source to share
If the order doesn't matter, you can enumerate backwards so that deleting doesn't mess up a part of the list that you haven't processed yet.
for i, item in enumerate(reversed(somelist), -len(somelist)+1):
do_some_stuff(item)
if delete_element(item):
del somelist[-i]
If order matters, reverse the list, do this trick, then reverse it again. This will confuse them!
Depending on the situation, you can replace the element with a marker such as None. Either cross it out later, or use other places where this list is used.
for i, item in enumerate(somelist)):
do_some_stuff(item)
if delete_element(item):
somelist[i] = None
somelist = [item for item in somelist if item]
source to share
You can split the operations into two separate loops and use a list comprehension for the second part.
for value in some_list:
do_some_stuff(value)
some_list = [value for value in some_list if not delete_element(value)]
Another solution would be to iterate over a copy of the list and use it enumerate
to keep track of the indexes without having to manually maintain the counter.
for index, value in enumerate(some_list[::-1]):
do_some_stuff(value)
if delete_element(value):
del some_list[-index - 1]
You want to iterate backwards, so you don't need to tweak index
for deleted items.
source to share
A hopeless way is to use a generator:
def do_stuff_and_filter_items(items):
for item in items:
do_some_stuff(item)
if not delete_element(item):
yield item
Then, to get the iterable:
items = do_stuff_and_filter_items(items)
or get a list:
items = list(do_stuff_and_filter_items(items))
or overwrite the old list:
items[:] = do_stuff_and_filter_items(items)
source to share