localizando e substituindo elementos em uma lista


273

Eu tenho que pesquisar uma lista e substituir todas as ocorrências de um elemento por outro. Até agora, minhas tentativas de código não me levaram a lugar algum, qual é a melhor maneira de fazer isso?

Por exemplo, suponha que minha lista tenha os seguintes números inteiros

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

e preciso substituir todas as ocorrências do número 1 pelo valor 10, para que a saída que eu preciso seja

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

Assim, meu objetivo é substituir todas as instâncias do número 1 pelo número 10.


11
O que é isso, a propósito?
outis 6/04/10

Respostas:


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 é uma solução ruim e muito não-pitônica. Considere usar a compreensão da lista.
AdHominem 31/12/16

204
Essa é uma solução ótima, embora não muito pitônica. Considere usar a compreensão da lista.
Jean-François Corbett

Considere usar a compreensão da lista, como é feito por @outis abaixo!
AMC

6
Isso funciona melhor do que a compreensão da lista, não é? Ele faz atualizações no local em vez de gerar uma nova lista.
Neverendingqs

@neverendingqs: Não. A sobrecarga de intérpretes domina a operação e a compreensão é menor. A compreensão apresenta um desempenho um pouco melhor, especialmente com uma proporção maior de elementos que passam na condição de substituição. Tenha alguns horários: ideone.com/ZrCy6z
user2357112 suporta Monica

519

Tente usar uma compreensão de lista e o operador ternário .

>>> 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
Mas isso não muda, acerto? Acho OP queria amudar
Dula

10
@Dula você pode fazer a = [4 if x == 1 pessoa x for x in a], isso afetará a
Alekhya Vemavarapu

@ Dula: a pergunta é vaga sobre se adeve sofrer uma mutação, mas (como mostra Alekhya) é trivial lidar com ambos os casos ao usar uma lista de compreensão.
Outis

34
Se você deseja fazer a mutação a, deve fazê-lo a[:] = [4 if x==1 else x for x in a](observe a fatia da lista completa). Basta fazer o a =vai criar uma nova lista acom um diferente id()(identidade) do original
Chris_Rands

39

A compreensão da lista funciona bem e o looping com o enumerate pode economizar um pouco de memória (porque basicamente a operação está sendo executada no local).

Há também programação funcional. Veja o uso do 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. É muito ruim lambdae mapé considerado antitônico.
Out

4
Não tenho certeza de que o lambda ou o mapa sejam inerentemente antitônicos, mas concordo que a compreensão da lista é mais limpa e legível do que usar os dois em conjunto.
damzam

7
Eu não os considero antitônicos, mas muitos o consideram, incluindo Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). É uma daquelas coisas sectárias.
outis 8/04/10

36

Se você tiver vários valores para substituir, também poderá usar um dicionário:

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
Isso não gera um erro se nnão for encontrado dic?
21416 Neil A.

3
@ user2914540 Melhorei um pouco sua resposta para que funcione se nnão for encontrada. Espero que você não se importe. Sua try/exceptsolução não foi boa.
Jrjc

Ah, sim, está melhor.
roipoussiere

1
@jrjc @roipoussiere para substituições no local, try-excepté pelo menos 50% mais rápido! Dê uma olhada nesta resposta
lifebalance 23/11

4
if n in dic.keys()é ruim em termos de desempenho. Use if n in dicor dic.get(n,n)(valor padrão)
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 médio rápido, mas muito sensível. Por favor, veja horários na minha resposta.
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

Você pode usar um loop for e ou while; no entanto, se você conhece a função Enumerar interna, é recomendável usar Enumerar. 1


1
Essa é a única maneira sã (legível) de fazer isso quando você precisar executar operações mais complexas nos itens da lista. Por exemplo, se cada item da lista for uma cadeia longa que precise de algum tipo de pesquisa e substituição.
Not2qubit #

8

Para substituir facilmente todos 1com 10em a = [1,2,3,4,5,1,2,3,4,5,1]um poderia usar a combinação lambda + mapa de uma linha seguinte, e 'Olha, Ma, há FI ou 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))


Método mais lento de longe. Você está chamando um lambdaelemento em cada lista ...
dawg

4

A seguir, é um método muito direto no 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. Comentários são bem-vindos. Espero que ajude :)

Além disso, tente entender como Outis do e do damzam soluções trabalho. As compressões de lista e a função lambda são ferramentas úteis.


4

Em listas longas e ocorrências raras, o uso é cerca de 3x mais rápido list.index()- comparado aos métodos de iteração de etapa única apresentados nas outras respostas.

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 é o método mais rápido que encontrei. Por favor, veja horários na minha resposta. Ótimo!
dawg

3

Eu sei que essa é uma pergunta muito antiga e há inúmeras maneiras de fazer isso. O mais simples que encontrei está usando o numpypacote.

import numpy

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

3

Meu caso de usuário foi substituído Nonepor algum valor padrão.

Eu cronometrei abordagens para esse problema que foram apresentadas aqui, incluindo a do @kxr - using str.count.

Código de teste no ipython com 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)    

Eu recebo:

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 o interno str.indexé de fato mais rápido do que qualquer comparação manual.

Eu não sabia se a exceção no teste 4 seria mais trabalhosa do que em usar str.count, a diferença parece insignificante.

Observe que map()(teste 6) retorna um iterador e não uma lista real, portanto, teste 7.


2

Você pode simplesmente usar a compreensão da lista em python:

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

para o seu caso, onde você deseja substituir todas as ocorrências de 1 por 10, o snippet de código será assim:

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
Embora esse trecho de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código. Tente também não sobrecarregar seu código com comentários explicativos, pois isso reduz a legibilidade do código e das explicações!
Filnor

-1

Encontre e substitua apenas um item

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]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.