Introduction
A reasonably frequent job an engineer could must do is to take away all numbers from a listing under a threshold. It is a easy sufficient job that anybody may accomplish – iterate over the checklist, examine the worth, if it is under the edge take away it. With Python you are able to do this in a for loop.
Gotcha
Let’s examine code for this easy downside.
numbers_list = [0, 9, 2, 1, 5, 1, 10, 4, 3]
for index, worth in enumerate(numbers_list):
print(index, worth, worth < 5, 'Deleted' if worth < 5 else 'Stored')
if worth < 5:
del(numbers_list[index])
print(numbers_list)
It would be affordable to count on an remaining checklist that appears like this:
However, the precise output is:
What’s taking place?
Explaination
The (unconsious?) assumption that the developer is making with this piece of code is that the ultimate checklist should be in numbers_list. Since we’re in a position to iterate and modify, there isn’t a want for a short lived variable or a necessity to fret about checklist copy gotchas. However, let’s undergo this one iteration at a time.
Beginning checklist: [0, 9, 2, 1, 5, 1, 10, 4, 3]
| Iteration | Index | Worth | Worth < 5? | Motion | Listing after iteration |
| --------- | ----- | ----- | ---------- | ------ | ------------------------- |
| 0 | 0 | 0 | True | Delete | [9, 2, 1, 5, 1, 10, 4, 3] |
| 1 | 1 | 2 | True | Delete | [9, 1, 5, 1, 10, 4, 3] |
| 2 | 2 | 5 | False | Preserve | [9, 1, 5, 1, 10, 4, 3] |
| 3 | 3 | 1 | True | Delete | [9, 1, 5, 10, 4, 3] |
| 4 | 4 | 4 | True | Delete | [9, 1, 5, 10, 3] |
Finish of iteration as checklist has no extra components
this, it is somewhat clearer what is going on on. Let’s undergo there one iteration at a time.
- On the primary iteration, the worth of
Index 0is0, so it is deleted. And the issue begins now. - On the subsequent iteration, the worth of
Index 1is2(not 9). Within the earlier iteration,Index 0was deleted, which suggests the whole lot has moved up one index. The worth of9was by no means checked. As a substitute, we have a look at a worth of2. It is lower than our threshold so it is also deleted. - On the third iteration, the worth of
Index 2is5. Once more, we have skipped a worth (1) and it is by no means even checked. This iteration would not end in a deletion as a result of5isn’t lower than5. - On the forth iteration, the worth of
Index 3is1. That is deleted as anticipated. - On the fifth iteration, the worth of
Index 4is4. We have skipped one other worth (10) and this iteration’s worth is lower than our threshold so it is deleted. - There isn’t a additional iteration, as a result of the final one has made the ultimate worth the final index, so the ultimate worth isn’t checked.
We skipped checking a number of values as a result of we messed with indexes that had been both being operated on or hadn’t been operated on but. This leads to sudden habits.
Answer
A fast answer is so as to add the values that exceed our threshold to a different variable:
numbers_list = [0, 9, 2, 1, 5, 1, 10, 4, 3]
larger_list = []
for index, worth in enumerate(numbers_list):
if worth >= 5:
larger_list.append(worth)
print(larger_list)
This leads to the anticipated checklist of [9, 5, 10]
One other answer, assuming that the consequence wants to sit down in a variable with the identical identify, is to make use of a listing comprehension. This does the identical factor as above, however retains the code extra compact. It additionally works as a result of the ultimate result’s assigned to a brand new variable object with the identical identify.
numbers_list = [0, 9, 2, 1, 5, 1, 10, 4, 3]
numbers_list = [nums for nums in numbers_list if nums >= 5]
print(numbers_list)
This leads to the anticipated checklist of [9, 5, 10]
