2009-10-08 12 views
88

Tengo una lista en la que deseo reemplazar los valores por None donde condition() devuelve True.Reemplazar valores en la lista usando Python

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

Por ejemplo, si la condición cheques bool (elemento% 2) debe devolver:

[None, 1, None, 3, None, 5, None, 7, None, 9, None] 

¿Cuál es la forma más eficiente de hacer esto?

+0

utiliza el módulo itertools, es el más eficiente. – LtWorf

+1

Para las comparaciones de reemplazo 'en el lugar ', échele un vistazo a esta [respuesta] (http://stackoverflow.com/a/24203748/307454) – lifebalance

Respuesta

130

construir una nueva lista con una lista por comprensión:

new_items = [x if x % 2 else None for x in items] 

puede modificar la lista original en el lugar si lo desea, pero no es así en realidad ahorrar 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 (Python 3.6.3) temporizaciones que demuestran el 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) 

y Python 2.7.6 horarios:

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 
+2

¿es la más eficiente? no enumera tiene que crear un iterador y formar una tupla, ¿agregar sobrecarga? ¿Hay listas en listas de matrices de python, que le brindan acceso de tiempo constante? – geowa4

+0

Creo, y podría estar equivocado, que quería que se devolviera una copia de la lista en lugar de modificar el original. Pero aún así, +1 por ofrecer la solución eficiente cuando se permite la modificación in situ. –

+0

Si quisiera modificar el original en su lugar, ¿no sería posible también usar imap desde itertools? –

2
>>> 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] 
53
ls = [x if (condition) else None for x in ls] 
10

riffs en una pregunta formulada por el lado OP en un comentario, es decir:

lo que si tuviera un generador que produce los valores del rango (11) en lugar de una lista . ¿Sería posible reemplazar los 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 

sólo tiene que pasar cualquier iterable (incluyendo el resultado de llamar a un generador) como el primer argumento, el predicado para decidir si un valor debe ser reemplazado como segundo arg, y vamos a rasgar.

Por ejemplo:

>>> list(replaceiniter(xrange(11), lambda x: x%2)) 
[0, None, 2, None, 4, None, 6, None, 8, None, 10] 
+0

+1 jeje ... quiero aprender a escribir esta línea" uno "ingeniosa solución python ... sugerencia pls – gath

+0

@gath, no entiendo su pregunta - los comentarios son bastante limitado por lo que debe abrir una nueva pregunta para que pueda ampliar y aclarar qué es lo que está buscando ... –

8

Ésta es otra manera:

>>> L = range (11) 
>>> map(lambda x: x if x%2 else None, L) 
[None, 1, None, 3, None, 5, None, 7, None, 9, None] 
+1

+1 y cómo aprenden los hombres este código de pitón ingenioso de una línea ... insinuaciones – gath

+5

@gath: Don ' aspiro a escribir frases ingeniosas para cada propósito. A veces, aumentan la legibilidad o el rendimiento, pero a menudo no lo hacen. En cuanto a consejos: Conozca las herramientas con las que Python ofrece, especialmente la lista (y para Python 3 también dict) las comprensiones, el operador ternario, las funciones anónimas (lambda) y funciones como mapa, zip, filtro, reducir, etc. – balpha

2

Esto podría ayudar ...

test_list = [5, 8] 
test_list[0] = None 
print test_list 
#prints [None, 8] 
+1

Can ¿Explicas por qué crees que podría ser útil? –

+0

@ T-Heron Se podría modificar para cumplir con lo que la pregunta está pidiendo – Emil

+0

Si necesita ser * modificado *, entonces no es una respuesta a la pregunta que se está haciendo. Haga (o explique) las modificaciones necesarias usted mismo o elimine la respuesta. –

0

En caso de que quiera reemplazar los valores en su lugar, se puede actualice su lista original con los valores de una lista comprehensi en por asignando a 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, que escribió data2=data antes de cambiar la lista y se salta la notación rebanada de asignar a data, data se vuelva a enlazar para que apunte a la recién creada lista mientras data2 aún apunta a la lista original 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: Esta no es una recomendación para general preferir uno sobre el otro (lista de cambiar en su sitio o no), pero el comportamiento que debe tener en cuenta.

Cuestiones relacionadas