diff options
author | 2024-04-16 11:54:59 -0400 | |
---|---|---|
committer | 2024-04-16 11:54:59 -0400 | |
commit | 913f24043414307d8feb20f43f46e7006c7c0feb (patch) | |
tree | f10b6910c52bd18559aa43c3a326df51767ada9a | |
parent | Merge pull request #2982 from python-discord/vivek/fix-phishing-button (diff) |
feat: tag loop-remove
details the gotcha of removing items from a collection
while iterating that collection inside a for loop.
-rw-r--r-- | bot/resources/tags/loop-remove.md | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/bot/resources/tags/loop-remove.md b/bot/resources/tags/loop-remove.md new file mode 100644 index 000000000..0fb22a06b --- /dev/null +++ b/bot/resources/tags/loop-remove.md @@ -0,0 +1,42 @@ +--- +embed: + title: "Removing items inside a for loop" +--- +Avoid removing items from a collection, such as a list, as you iterate that collection in a `for` loop: + +```py +# Don't do this! +data = [1, 2, 3, 4] +for item in data: + data.remove(item) + +print(data) +# [2, 4] # <- every OTHER item was removed! +``` + +`for` loops track the index of the current item with a kind of pointer. Removing an element causes all other elements to shift, but the pointer is not changed: + +```py +# Start the loop: +[1, 2, 3, 4] # First iteration: point to the first element + ^ +[2, 3, 4] # Remove current: all elements shift + ^ +[2, 3, 4] # Next iteration: move the pointer + ^ +[2, 4] # Remove current: all elements shift + ^ +# Done +``` + +You can avoid this pitfall by: +- using a list comprehension to produce a new list (as a way of filtering items): + ```py + data = [x for x in data if x % 2 == 0] + ``` +- using a `while` loop and `.pop()` (treating the list as a stack): + ```py + while data: + item = data.pop() + ``` +- consider: you may not need to remove items in the first place! |