可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答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
回答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])
回答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.])
回答4:
Is this what you're looking for? Make a list of the indexes you want to change, and then loop through that list to change the values.
els_to_replace = [0, 1, 3]
mylist = [0, 0, 0, 0, 0]
for index in els_to_replace:
mylist[index] = 100
mylist
Out[9]: [100, 100, 0, 100, 0]
回答5:
I like a list comprehension:
[100 if index in [1, 4] else 0 for index, x in enumerate(mylist) ]
回答6:
Not a huge fan of this one, but you could try this (although I think all of the above are much more concise and easy to read):
In [22]: from operator import setitem
In [23]: mylist = [0, 0, 0, 0, 0]
In [24]: indeces_to_replace = [0, 1, 3]
In [25]: _ = map(lambda x: setitem(mylist, x, 100), indeces_to_replace)
In [26]: mylist
Out[26]: [100, 100, 0, 100, 0]
Aside from the questionable readability and need for an import, @abarnert pointed out a few additional issues, namely that map
still creates an unnecessary list (which is discarded with the _
but created nonetheless) and that it won't work in Python 3 because map
returns an iterator in Python 3.x. You can use the six module to simulate the behavior of map
in Python 3.x from Python 2.x, and in combination with collections.deque
(again as suggested by @abarnert), you can achieve the same output without creating the additional list in memory because a deque
that can contain a maximum of 0
items will discard everything it receives from the map
iterator (note that with six
, map
is simulated by using itertools.imap
).
Again, there is absolutely no need to ever use this - every solution above/below is better :)
In [1]: from collections import deque
In [2]: from six.moves import map
In [3]: from operator import setitem
In [4]: mylist = [0, 0, 0, 0, 0]
In [5]: indeces_to_replace = [0, 1, 3]
In [6]: deque(map(lambda x: setitem(mylist, x, 100), indeces_to_replace), maxlen=0)
Out[6]: deque([], maxlen=0)
In [7]: mylist
Out[7]: [100, 100, 0, 100, 0]