Replacing selected elements in a list in Python
Solution 1
Especially since you're replacing a sizable chunk of the list
, I'd do this immutably:
mylist = [100 if i in (0, 1, 3) else e for i, e in enumerate(mylist)]
It's intentional in Python that making a new list
is a one-liner, while mutating a list
requires an explicit loop. Usually, if you don't know which one you want, you want the new list
. (In some cases it's slower or more complicated, or you've got some other code that has a reference to the same list
and needs to see it mutated, or whatever, which is why that's "usually" rather than "always".)
If you want to do this more than once, I'd wrap it up in a function, as Volatility suggests:
def elements_replaced(lst, new_element, indices):
return [new_element if i in indices else e for i, e in enumerate(lst)]
I personally would probably make it a generator so it yields an iteration instead of returning a list, even if I'm never going to need that, just because I'm stupid that way. But if you actually do need it:
myiter = (100 if i in (0, 1, 3) else e for i, e in enumerate(mylist))
Or:
def elements_replaced(lst, new_element, indices):
for i, e in enumerate(lst):
if i in indices:
yield new_element
else:
yield e
Solution 2
def replace_element(lst, new_element, indices):
for i in indices:
lst[i] = new_element
return lst
It's definitely a more general solution, not a one-liner though. For example, in your case, you would call:
mylist = replace_element(mylist, 100, [0, 1, 3])
Solution 3
Numpy supports this if you're not opposed to using an np.ndarray
:
>>> a = np.zeros(5)
>>> a[[0,1,3]] = 100
>>> a
array([ 100., 100., 0., 100., 0.])
elwc
Updated on January 16, 2020Comments
-
elwc over 4 years
I have a list:
mylist = [0, 0, 0, 0, 0]
I only want to replace selected elements, say the first, second, and fourth by a common number,
A = 100
.One way to do this:
mylist[:2] = [A]*2 mylist[3] = A mylist [100, 100, 0, 100, 0]
I am looking for a one-liner, or an easier method to do this. A more general and flexible answer is preferable.
-
elwc over 11 yearsGood explanation regarding the new list and mutation.
-
abarnert over 11 years+1. On top of being more general, I think this is the most readable way to do the mutable replacement, despite (or, rather, probably because of) not being a one-liner.
-
Abhijit over 11 yearsSometimes I do miss the
valarray::gslice
-
abarnert over 11 years@Abhijit: Well, nearly every case where
valarray
makes sense in C++,numpy
makes sense in Python—andnumpy
's extended slicing is even simpler thangslice
for almost all cases. For example, see mgilson's answer to this question. (Of course "nearly every" and "almost all" aren't quite the same as "every" and "all"… but it's rare that I find myself writing somenumpy
code and missing a C++ feature…) -
abarnert over 11 yearsThe main problem with this is that in Python 3, it doesn't work, because you just get back an iterator that you never iterate. The lesser problem is that in Python 2, it builds a list you have no need for. You can solve the first problem by explicitly doing
list(map(…))
. Or you can solve both by usingsix.map
and passing the result to aniter_discard
function, which you can implement ascollections.deque(it, max_size=0)
. Which is all a whole lot more thought than you should ever put into a solution you weren't a huge fan of in the first place, of course… -
abarnert over 11 years+1. Even if this doesn't directly answer the OP's question (and I'm not sure it doesn't), whenever you find yourself dealing with sequences of numbers and something seems harder than it should be, the first question you should ask is probably "am I opposed to using an
np.ndarray
here?" -
RocketDonkey over 11 years@abarnert Belated +1 to your answer (informative as always), and great points regarding this implementation (never thought about passing the results of
map
to aniter_discard
function). I'll add in an update for posterity's sake, and thanks as always for the helpful info :) -
abarnert over 11 yearsI really wish
iter_discard
were part of the 3.x standard library. The argument against it was that this would want to encourage people usingmap
for side effects instead of results (and, if you really want it, thedeque
trick has been added to the documentation foritertools
somewhere). I can buy that… but for these kinds of questions, people always do that anyway (and then want totimeit
the results with every version of Python they can find). -
RocketDonkey over 11 years@abarnert Right you are, looks like the
consume
recipe. That is interesting - I have always felt like I was doing something not-quite-right when usingmap
for the side effects you mention (the unnecessary list byproduct being the strongest indicator). Thatdeque
technique definitely alleviates that feeling, so thanks for the new trick to add to the rotation :)