encontrar y reemplazar elementos en una lista


273

Tengo que buscar en una lista y reemplazar todas las ocurrencias de un elemento con otro. Hasta ahora, mis intentos en el código no me llevan a ninguna parte, ¿cuál es la mejor manera de hacer esto?

Por ejemplo, supongamos que mi lista tiene los siguientes enteros

>>> a = [1,2,3,4,5,1,2,3,4,5,1]

y necesito reemplazar todas las apariciones del número 1 con el valor 10, por lo que la salida que necesito es

>>> a = [10, 2, 3, 4, 5, 10, 2, 3, 4, 5, 10]

Por lo tanto, mi objetivo es reemplazar todas las instancias del número 1 con el número 10.


11
¿Para qué es esto, por cierto?
outis

Respuestas:


250
>>> a= [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1]
>>> for n, i in enumerate(a):
...   if i == 1:
...      a[n] = 10
...
>>> a
[10, 2, 3, 4, 5, 10, 2, 3, 4, 5, 10]

15
Esta es una solución mala y muy poco pitónica. Considere usar la comprensión de la lista.
AdHominem

205
Esta es una buena solución, aunque muy poco pitónica. Considere usar la comprensión de la lista.
Jean-François Corbett

¡Considere usar la comprensión de la lista, como lo hace @outis a continuación!
amc

66
Esto funciona mejor que la comprensión de la lista, ¿no es así? Realiza actualizaciones en el lugar en lugar de generar una nueva lista.
neverendingqs

@neverendingqs: No. La sobrecarga del intérprete domina la operación, y la comprensión tiene menos. La comprensión funciona ligeramente mejor, especialmente con una mayor proporción de elementos que pasan la condición de reemplazo. Tenga algunos horarios: ideone.com/ZrCy6z
user2357112 apoya a Monica el

519

Intente usar una lista de comprensión y el operador ternario .

>>> a=[1,2,3,1,3,2,1,1]
>>> [4 if x==1 else x for x in a]
[4, 2, 3, 4, 3, 2, 4, 4]

9
Pero esto no cambia, a¿verdad? Creo que OP quería acambiar
Dula

10
@Dula puede hacer a = [4 si x == 1 más x para x en a], esto afectará a
Alekhya Vemavarapu

@Dula: la pregunta es vaga en cuanto a si adebería mutar, pero (como lo muestra Alekhya) es trivial manejar cualquier caso cuando se utiliza una lista de comprensión.
outis

34
Si desea mutar a, debe hacerlo a[:] = [4 if x==1 else x for x in a](tenga en cuenta el segmento de la lista completa). Simplemente haciendo a =esto creará una nueva lista acon una id()(identidad) diferente de la original
Chris_Rands

39

La comprensión de la lista funciona bien, y recorrerla con enumerate puede ahorrarle algo de memoria (b / c, la operación se realiza esencialmente en el lugar).

También hay programación funcional. Ver uso del mapa :

>>> a = [1,2,3,2,3,4,3,5,6,6,5,4,5,4,3,4,3,2,1]
>>> map(lambda x: x if x != 4 else 'sss', a)
[1, 2, 3, 2, 3, 'sss', 3, 5, 6, 6, 5, 'sss', 5, 'sss', 3, 'sss', 3, 2, 1]

17
+1. Es una lástima lambday mapse consideran antifónicos.
outis

44
No estoy seguro de que lambda o mapa sea intrínsecamente no pitónico, pero estoy de acuerdo en que una comprensión de la lista es más limpia y más legible que usar los dos en conjunto.
damzam

77
Yo no los considero no pitónicos, pero muchos lo hacen, incluido Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). Es una de esas cosas sectarias.
outis

36

Si tiene varios valores para reemplazar, también puede usar un diccionario:

a = [1, 2, 3, 4, 1, 5, 3, 2, 6, 1, 1]
dic = {1:10, 2:20, 3:'foo'}

print([dic.get(n, n) for n in a])

> [10, 20, 'foo', 4, 10, 5, 'foo', 20, 6, 10, 10]

1
¿Esto no arroja un error si nno se encuentra en dic?
Neil A.

3
@ user2914540 Mejoré un poco tu respuesta para que funcione si nno se encuentra. Espero que no te moleste. Tu try/exceptsolución no fue buena.
jrjc

Oh sí, eso está mejor.
roipoussiere

1
@jrjc @roipoussiere para reemplazos en el lugar, ¡ try-exceptes al menos un 50% más rápido! Eche un vistazo a esta respuesta
balance de vida

44
if n in dic.keys()es malo en cuanto a rendimiento. Usar if n in dico dic.get(n,n)(valor predeterminado)
Jean-François Fabre

12
>>> a=[1,2,3,4,5,1,2,3,4,5,1]
>>> item_to_replace = 1
>>> replacement_value = 6
>>> indices_to_replace = [i for i,x in enumerate(a) if x==item_to_replace]
>>> indices_to_replace
[0, 5, 10]
>>> for i in indices_to_replace:
...     a[i] = replacement_value
... 
>>> a
[6, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6]
>>> 

Método medio rápido pero muy sensible. Por favor, vea los tiempos en mi respuesta.
dawg

10
a = [1,2,3,4,5,1,2,3,4,5,1,12]
for i in range (len(a)):
    if a[i]==2:
        a[i]=123

Puede usar un bucle for y or while; sin embargo, si conoce la función incorporada Enumerate, se recomienda usar Enumerate. 1


1
Esta es la única forma sensata (legible) de hacerlo cuando necesita realizar operaciones más complejas en los elementos de la lista. Por ejemplo, si cada elemento de la lista es una cadena larga que necesita algún tipo de búsqueda y reemplazo.
not2qubit

8

Para reemplazar fácilmente a todos 1con 10en a = [1,2,3,4,5,1,2,3,4,5,1]uno podría usar la siguiente combinación de una línea lambda + mapa, y 'Look, Ma, no hay FI o de Fors!' :

# This substitutes all '1' with '10' in list 'a' and places result in list 'c':

c = list(map(lambda b: b.replace("1","10"), a))


El método más lento con diferencia. Estás llamando a un lambdaelemento de cada lista ...
dawg

4

El siguiente es un método muy directo en Python 2.x

 a = [1,2,3,4,5,1,2,3,4,5,1]        #Replacing every 1 with 10
 for i in xrange(len(a)):
   if a[i] == 1:
     a[i] = 10  
 print a

Este método funciona Comentarios son bienvenidos Espero eso ayude :)

Prueba también la comprensión de cómo Outis de y de damzam soluciones de trabajo. Las compresiones de listas y la función lambda son herramientas útiles.


4

En listas largas y casos raros, su uso es aproximadamente 3 veces más rápido list.index(), en comparación con los métodos de iteración de un solo paso presentados en las otras respuestas.

def list_replace(lst, old=1, new=10):
    """replace list elements (inplace)"""
    i = -1
    try:
        while 1:
            i = lst.index(old, i + 1)
            lst[i] = new
    except ValueError:
        pass

Este es el método más rápido que he encontrado. Por favor, vea los tiempos en mi respuesta. ¡Excelente!
dawg

3

Sé que esta es una pregunta muy antigua y hay muchas formas de hacerlo. El más simple que encontré está usando el numpypaquete.

import numpy

arr = numpy.asarray([1, 6, 1, 9, 8])
arr[ arr == 8 ] = 0 # change all occurrences of 8 by 0
print(arr)

3

Mi caso de uso estaba reemplazando Nonecon algún valor predeterminado.

He cronometrado enfoques para este problema que se presentaron aquí, incluido el de @kxr - using str.count.

Código de prueba en ipython con Python 3.8.1:

def rep1(lst, replacer = 0):
    ''' List comprehension, new list '''

    return [item if item is not None else replacer for item in lst]


def rep2(lst, replacer = 0):
    ''' List comprehension, in-place '''    
    lst[:] =  [item if item is not None else replacer for item in lst]

    return lst


def rep3(lst, replacer = 0):
    ''' enumerate() with comparison - in-place '''
    for idx, item in enumerate(lst):
        if item is None:
            lst[idx] = replacer

    return lst


def rep4(lst, replacer = 0):
    ''' Using str.index + Exception, in-place '''

    idx = -1
    # none_amount = lst.count(None)
    while True:
        try:
            idx = lst.index(None, idx+1)
        except ValueError:
            break
        else:
            lst[idx] = replacer

    return lst


def rep5(lst, replacer = 0):
    ''' Using str.index + str.count, in-place '''

    idx = -1
    for _ in range(lst.count(None)):
        idx = lst.index(None, idx+1)
        lst[idx] = replacer

    return lst


def rep6(lst, replacer = 0):
    ''' Using map, return map iterator '''

    return map(lambda item: item if item is not None else replacer, lst)


def rep7(lst, replacer = 0):
    ''' Using map, return new list '''

    return list(map(lambda item: item if item is not None else replacer, lst))


lst = [5]*10**6
# lst = [None]*10**6

%timeit rep1(lst)    
%timeit rep2(lst)    
%timeit rep3(lst)    
%timeit rep4(lst)    
%timeit rep5(lst)    
%timeit rep6(lst)    
%timeit rep7(lst)    

Yo obtengo:

26.3 ms ± 163 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
29.3 ms ± 206 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
33.8 ms ± 191 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
11.9 ms ± 37.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
11.9 ms ± 60.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
260 ns ± 1.84 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
56.5 ms ± 204 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Usar el interno str.indexes, de hecho, más rápido que cualquier comparación manual.

No sabía si la excepción en la prueba 4 sería más laboriosa que usarla str.count, la diferencia parece insignificante.

Tenga en cuenta que map()(prueba 6) devuelve un iterador y no una lista real, por lo tanto, la prueba 7.


2

Simplemente puede usar la comprensión de listas en python:

def replace_element(YOUR_LIST, set_to=NEW_VALUE):
    return [i
            if SOME_CONDITION
            else NEW_VALUE
            for i in YOUR_LIST]

para su caso, donde desea reemplazar todas las apariciones de 1 por 10, el fragmento de código será así:

def replace_element(YOUR_LIST, set_to=10):
    return [i
            if i != 1  # keeps all elements not equal to one
            else set_to  # replaces 1 with 10
            for i in YOUR_LIST]

3
Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no saber los motivos de su sugerencia de código. ¡Intente también no saturar su código con comentarios explicativos, esto reduce la legibilidad tanto del código como de las explicaciones!
Filnor

-1

Encuentra y reemplaza solo un artículo

ur_list = [1,2,1]     # replace the first 1 wiz 11

loc = ur_list.index(1)
ur_list.remove(1)
ur_list.insert(loc, 11)

----------
[11,2,1]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.