I want to assign a single value to a part of a list. Is there a better solution to this than one of the following?
Maybe most performant but somehow ugly:
>>> l=[0,1,2,3,4,5]
>>> for i in range(2,len(l)): l[i] = None
>>> l
[0, 1, None, None, None, None]
Concise (but I don't know if Python recognizes that no rearrangement of the list elements is necesssary):
>>> l=[0,1,2,3,4,5]
>>> l[2:] = [None]*(len(l)-2)
>>> l
[0, 1, None, None, None, None]
Same caveat like above:
>>> l=[0,1,2,3,4,5]
>>> l[2:] = [None for _ in range(len(l)-2)]
>>> l
[0, 1, None, None, None, None]
Not sure if using a library for such a trivial task is wise:
>>> import itertools
>>> l=[0,1,2,3,4,5]
>>> l[2:] = itertools.repeat(None,len(l)-2)
>>> l
[0, 1, None, None, None, None]
The problem that I see with the assignment to the slice (vs. the for loop) is that Python maybe tries to prepare for a change in the length of "l". After all, changing the list by inserting a shorter/longer slice involves copying all elements (that is, all references) of the list AFAIK. If Python does this in my case too (although it is unnecessary), the operation becomes O(n) instead of O(1) (assuming that I only always change a handful of elements).
Simply select the slice you want to replace on the left and the values to replace it on the right side of the equation. For example, the slice assignment list[2:4] = [42, 42] replaces the list elements with index 2 and 3 with the value 42 . What is this?
“Indexing” means referring to an element of an iterable by its position within the iterable. “Slicing” means getting a subset of elements from an iterable based on their indices. By way of analogy, I was recently summoned to jury duty, and they assigned each potential juror a number.
Using the slice function to create a slice object can be useful if we want to save a specific slice object and use it multiple times. We can do so by first instantiating a slice object and assigning it to a variable, and then using that variable within square brackets.
The items at interval 2 starting from the last index are sliced. If you want the items from one position to another, you can mention them from start to stop . The items from index 1 to 4 are sliced with intervals of 2.
Timing it:
python -mtimeit "l=[0,1,2,3,4,5]" "for i in range(2,len(l)):" " l[i] = None"
1000000 loops, best of 3: 0.669 usec per loop
python -mtimeit "l=[0,1,2,3,4,5]" "l[2:] = [None]*(len(l)-2)"
1000000 loops, best of 3: 0.419 usec per loop
python -mtimeit "l=[0,1,2,3,4,5]" "l[2:] = [None for _ in range(len(l)-2)]"
1000000 loops, best of 3: 0.655 usec per loop
python -mtimeit "l=[0,1,2,3,4,5]" "l[2:] = itertools.repeat(None,len(l)-2)"
1000000 loops, best of 3: 0.997 usec per loop
Looks like l[2:] = [None]*(len(l)-2)
is the best of the options you provided (for the scope you are dealing with).
Note:
Keep in mind that results will vary based on Python version, operation system, other currently running programs, and most of all - the size of the list and of the slice to be replaced. For larger scopes probably the last option (using itertools.repeat
) will be the most effective, being both easily readable (pythonic) and efficient (performance).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With