renombrar - Reemplazar valores en la lista usando Python
recorrer data frame pandas (7)
Tengo una lista en la que deseo reemplazar los valores por None donde condition () devuelve True.
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Por ejemplo, si la condición comprueba bool (elemento% 2) debería devolver:
[None, 1, None, 3, None, 5, None, 7, None, 9, None]
¿Cuál es la forma más eficiente de hacer esto?
Aquí hay otra forma:
>>> L = range (11)
>>> map(lambda x: x if x%2 else None, L)
[None, 1, None, 3, None, 5, None, 7, None, 9, None]
Crea una nueva lista con una lista de comprensión:
new_items = [x if x % 2 else None for x in items]
Puede modificar la lista original in situ si lo desea, pero en realidad no ahorra tiempo:
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
Aquí están los tiempos de (Python 3.6.3) que demuestran el timeave:
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)
Y tiempos de Python 2.7.6:
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 loop
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]
...:
1000000 loops, best of 3: 1.14 µs per loop
En caso de que desee reemplazar los valores en su lugar, puede actualizar su lista original con los valores de una lista de comprensión mediante la asignación de la porción entera del original.
data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
id_before = id(data)
data[:] = [x if x % 2 else None for x in data]
data
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None]
id_before == id(data) # check if list is still the same
# Out: True
Si tiene varios nombres que apuntan a la lista original, por ejemplo, usted escribió data2=data
antes de cambiar la lista y omite la notación de división para asignar data
, los data
volverán a enlazar para apuntar a la lista recién creada mientras data2
aún apunta al original lista sin cambios.
data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
data2 = data
id_before = id(data)
data = [x if x % 2 else None for x in data] # no [:] here
data
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None]
id_before == id(data) # check if list is still the same
# Out: False
data2
# Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Nota: Esto no es una recomendación para generalmente preferir uno sobre el otro (cambiar la lista en su lugar o no), sino un comportamiento que debe tener en cuenta.
Esto podría ayudar ...
test_list = [5, 8]
test_list[0] = None
print test_list
#prints [None, 8]
Riffing en una pregunta lateral formulada por el OP en un comentario, es decir:
¿Y si tuviera un generador que arroje los valores del rango (11) en lugar de una lista? ¿Sería posible reemplazar valores en el generador?
Claro, es trivialmente fácil ...
def replaceiniter(it, predicate, replacement=None):
for item in it:
if predicate(item): yield replacement
else: yield item
Simplemente pase cualquier iterable (incluido el resultado de llamar a un generador) como la primera arg, el predicado para decidir si un valor debe ser reemplazado como la segunda arg, y deje que se rompa.
Por ejemplo:
>>> list(replaceiniter(xrange(11), lambda x: x%2))
[0, None, 2, None, 4, None, 6, None, 8, None, 10]
>>> L = range (11)
>>> [ x if x%2 == 1 else None for x in L ]
[None, 1, None, 3, None, 5, None, 7, None, 9, None]
ls = [x if (condition) else None for x in ls]