Replace values in list using Python [duplicate]
Build a new list with a list comprehension:
new_items = [x if x % 2 else None for x in items]
You can modify the original list in-place if you want, but it doesn't actually save time:
items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]for index, item in enumerate(items): if not (item % 2): items[index] = None
Here are (Python 3.6.3) timings demonstrating the non-timesave:
In [1]: %%timeit ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ...: for index, item in enumerate(items): ...: if not (item % 2): ...: items[index] = None ...:1.06 µs ± 33.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)In [2]: %%timeit ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ...: new_items = [x if x % 2 else None for x in items] ...:891 ns ± 13.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
And Python 2.7.6 timings:
In [1]: %%timeit ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ...: for index, item in enumerate(items): ...: if not (item % 2): ...: items[index] = None ...: 1000000 loops, best of 3: 1.27 µs per loopIn [2]: %%timeit ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ...: new_items = [x if x % 2 else None for x in items] ...: 1000000 loops, best of 3: 1.14 µs per loop
Riffing on a side question asked by the OP in a comment, i.e.:
what if I had a generator that yields the values from range(11) instead of a list. Would it be possible to replace values in the generator?
Sure, it's trivially easy...:
def replaceiniter(it, predicate, replacement=None): for item in it: if predicate(item): yield replacement else: yield item
Just pass any iterable (including the result of calling a generator) as the first arg, the predicate to decide if a value must be replaced as the second arg, and let 'er rip.
For example:
>>> list(replaceiniter(xrange(11), lambda x: x%2))[0, None, 2, None, 4, None, 6, None, 8, None, 10]