Reputation: 1123
Consider this:
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
These are correct statements in Python to remove elements:
numbers[0:2] = []
numbers[3:5] = []
However the statement below is not allowed:
numbers[::2] = []
ValueError: attempt to assign sequence of size 0 to extended slice of size 5
What prevents such a statement in Python?
Upvotes: 2
Views: 588
Reputation: 39
You have to create a new list with the slicing already mentioned in other answers:
numbers = numbers[1::2]
if you work on the same list you incur into heavy performance loss because inserting or deleting (not appending!) an element to a list is O(N). Since you have O(N) for each insertion and you have N/2 insertions your total cost is O(N**2). You really don't want that cost. Creating a new list with the output of the slicing, on the other hand, has just O(N) total cost.
Upvotes: 1
Reputation: 10719
ValueError: attempt to assign sequence of size 0 to extended slice of size 5
What prevents such a statement in Python?
It is noted in the documentation that the replacement must have the same length for the case where there is an explicit step (which is 2
in your case).
Operation | Result | Notes |
---|---|---|
s[i:j] = t | slice of s from i to j is replaced by the contents of the iterable t | |
s[i:j:k] = t | the elements of s[i:j:k] are replaced by those of t | (1) t must have the same length as the slice it is replacing. |
The correct way is also documented there.
Operation | Result | Notes |
---|---|---|
del s[i:j] | same as s[i:j] = [] | |
del s[i:j:k] | removes the elements of s[i:j:k] from the list |
Code:
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
del numbers[::2]
print(numbers)
Output:
[1, 3, 5, 7, 9]
Upvotes: 5
Reputation: 51162
There is no need for numbers[::2] = []
to have the behaviour of deleting every second element, because you can already do that by writing numbers[:] = numbers[1::2]
. If instead you want to (e.g.) replace every second element with the value 1
, you can write one of the below, which are explicit about their behaviour.
for i in range(0, len(numbers), 2):
numbers[i] = 1
# or:
numbers[::2] = [1] * len(numbers[::2])
It is not obvious what the correct behaviour should be for assigning m
elements to a non-contiguous slice of n
list locations when m != n
. In the comments you propose a possible behaviour, but your proposal is not consistent with how slice assignment works in other cases (normally, each element on the right-hand side gets used once on the left-hand side) and certainly doesn't fulfil the principle of least astonishment. In cases like this, I think there is no (non-raising) behaviour that most people would expect, so raising an error is the best option.
Upvotes: 3