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.

James
fuente
11
¿Para qué es esto, por cierto?
outis
Duplicado de stackoverflow.com/q/1540049/819417
Cees Timmerman

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]
ghostdog74
fuente
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]
outis
fuente
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]
Damzam
fuente
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]
roipoussiere
fuente
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]
>>> 
John La Rooy
fuente
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

Eimal Dorani
fuente
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))

J.Paul
fuente
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.

Ananay Mital
fuente
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
kxr
fuente
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)
Tiago Vieira
fuente
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.

Arrendajo
fuente
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]
bassel7
fuente
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]
bereket gebredingle
fuente