How to remove multiple items from a list in just one statement?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Removing multiple items from a Python list is one of those tasks that looks simple but hides real performance traps. The naive approach -- looping and calling remove() one at a time -- is both verbose and slow because each remove() scans the entire list. Understanding the one-statement alternatives matters because choosing the wrong technique on a large dataset can turn a millisecond operation into one that takes minutes.
List Comprehension Filter
The most Pythonic way to remove multiple items is a list comprehension that keeps only the values you want. This works because it is easier to think about what to keep than what to discard, and it produces a clean new list in a single expression.
Notice that unwanted is a set, not a list. This is the single most important performance detail in this pattern. Checking membership in a set is O(1) on average, while checking membership in a list is O(n). For a list of 100,000 items with 10,000 to remove, this difference is enormous.
Set Difference
When your list contains unique elements and order does not matter, set arithmetic gives you the most concise syntax.
The tradeoff is clear: you lose the original ordering and any duplicate values. If either of those matters to your use case, stick with the list comprehension approach.
Using the filter() Function
The built-in filter() function offers a functional programming style alternative. It takes a predicate function and an iterable, returning only the elements where the predicate is True.
This is functionally identical to the list comprehension version. Most Python developers prefer the comprehension for readability, but filter() can be useful when you already have a named predicate function to pass in.
Removing by Index
Sometimes you need to remove items at specific positions rather than by value. This requires a different strategy because deleting an element shifts all subsequent indices.
The safest one-statement approach is to build a new list that skips the unwanted indices:
If you must modify the list in place (for example, when other references point to the same list object), delete from the highest index to the lowest so that earlier indices remain valid:
For NumPy arrays, numpy.delete handles this natively:
Removing by Value with In-Place Mutation
If you need to modify the original list object rather than create a new one, slice assignment with a comprehension is the one-liner:
The original[:] = ... syntax replaces the contents of the existing list object in place. Any other variable referencing the same list will see the updated contents. This distinction matters when you pass lists to functions or store them in shared data structures.
Performance Comparison
The reason the choice of data structure for unwanted matters so much comes down to algorithmic complexity. Here is a practical comparison:
On a typical machine, the list lookup version takes several seconds while the set version completes in milliseconds. The lesson is simple: always convert your removal targets to a set before filtering.
| Method | Preserves Order | In-Place | Time Complexity |
| List comprehension + set | Yes | No | O(n) |
| Slice assignment + set | Yes | Yes | O(n) |
| Set difference | No | No | O(n) |
| filter() + set | Yes | No | O(n) |
| Repeated list.remove() | Yes | Yes | O(n * k) |
In this table, n is the length of the original list and k is the number of items to remove.
Common Pitfalls
- Using a list instead of a set for the removal targets: This turns an O(n) operation into O(n * k) because each
incheck scans the entire removal list. - Modifying a list while iterating over it: Deleting elements during a forward loop skips items and produces wrong results. Always iterate in reverse or build a new list.
- Forgetting that list comprehension creates a new object: If other variables reference the original list, they will not see the changes. Use
original[:] = ...for in-place mutation. - Using set difference when order matters:
set(original) - to_removediscards the original ordering and eliminates duplicates, which silently corrupts data if you did not expect it. - Calling remove() in a loop for duplicate values:
list.remove()only deletes the first occurrence. If the value appears multiple times, you need multiple calls or a comprehension-based approach.
Summary
- List comprehension with a set of unwanted values (
[x for x in lst if x not in bad_set]) is the standard one-statement pattern for removing multiple items. - Always convert your removal targets to a
setfor O(1) membership checks. - Use
original[:] = ...when you need in-place mutation that propagates to all references. - Set difference is the most concise option but sacrifices ordering and deduplicates your data.
- For index-based removal, enumerate and skip unwanted indices, or delete in reverse order to keep indices stable.
- Avoid calling
list.remove()in a loop -- it is both slower and more error-prone than any of the one-statement alternatives.

