trovare e sostituire elementi in un elenco


273

Devo cercare in un elenco e sostituire tutte le occorrenze di un elemento con un altro. Finora i miei tentativi nel codice non mi stanno portando da nessuna parte, qual è il modo migliore per farlo?

Ad esempio, supponiamo che la mia lista abbia i seguenti numeri interi

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

e devo sostituire tutte le occorrenze del numero 1 con il valore 10, quindi l'output di cui ho bisogno è

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

Quindi il mio obiettivo è sostituire tutte le istanze del numero 1 con il numero 10.


11
A cosa serve, comunque?
uscita

Risposte:


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
Questa è una soluzione cattiva e molto non-pitonica. Prendi in considerazione l'utilizzo della comprensione dell'elenco.
AdHominem,

205
Questa è un'ottima soluzione se non molto pitonica. Prendi in considerazione l'utilizzo della comprensione dell'elenco.
Jean-François Corbett,

Prendi in considerazione l'utilizzo della comprensione dell'elenco, ad esempio @outis di seguito!
amc

6
Ciò si comporta meglio della comprensione dell'elenco sebbene non sia così? Effettua aggiornamenti sul posto invece di generare un nuovo elenco.
Neverendingqs

@neverendingqs: No. Il sovraccarico dell'interprete domina l'operazione e la comprensione ne ha di meno. La comprensione funziona leggermente meglio, specialmente con una proporzione più elevata di elementi che superano la condizione di sostituzione. Avere dei tempi: ideone.com/ZrCy6z
user2357112 supporta Monica

519

Prova a usare una comprensione dell'elenco e l' operatore 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
Ma questo non cambia, agiusto? Penso che OP volesse acambiare
Dula,

10
@Dula puoi fare a = [4 se x == 1 altro x per x in a], questo avrà effetto a
Alekhya Vemavarapu

@Dula: la domanda è vaga se si adebba mutare, ma (come mostra Alekhya) è banale gestire entrambi i casi quando si usa una comprensione della lista.
uscita

34
Se vuoi mutare, aallora dovresti farlo a[:] = [4 if x==1 else x for x in a](nota l'intera sezione dell'elenco). Basta fare la a =volontà per creare un nuovo elenco acon una id()(identità) diversa da quella originale
Chris_Rands

39

La comprensione dell'elenco funziona bene e il ciclo con enumerate può farti risparmiare un po 'di memoria (b / c l'operazione essenzialmente viene eseguita sul posto).

C'è anche una programmazione funzionale. Vedi l'utilizzo della mappa :

>>> 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. È troppo male lambdae mapsono considerati non ritonici.
uscita

4
Non sono sicuro che lambda o mappa siano intrinsecamente non pitonici, ma concordo sul fatto che la comprensione di un elenco sia più chiara e leggibile rispetto all'utilizzo congiunto di entrambi.
damzam,

7
Non li ritengo non ritmici, ma molti lo fanno, incluso Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). È una di quelle cose settarie.
uscita

36

Se hai diversi valori da sostituire, puoi anche usare un dizionario:

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
Questo non genera un errore se nnon viene trovato in dic?
Neil A.

3
@ user2914540 Ho migliorato un po 'la tua risposta, quindi funziona se nnon viene trovata. Spero non ti dispiaccia. La tua try/exceptsoluzione non è stata buona.
jrjc,

Oh sì, va meglio.
Roipoussiere,

1
@jrjc @roipoussiere per le sostituzioni sul posto, try-exceptè almeno il 50% più veloce! Dai un'occhiata a questa risposta
equilibrio di vita

4
if n in dic.keys()è male dal punto di vista delle prestazioni. Usa if n in dico dic.get(n,n)(valore predefinito)
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]
>>> 

Metodo medio veloce ma molto sensibile. Si prega di vedere i tempi nella mia risposta.
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

Puoi usare un ciclo for e oppure while; tuttavia se si conosce la funzione Enumerate integrata, si consiglia di utilizzare Enumerate. 1


1
Questo è l'unico modo sano (leggibile) per farlo quando è necessario eseguire operazioni più complesse sugli elementi dell'elenco. Ad esempio, se ogni elemento dell'elenco è una stringa lunga che necessita di un tipo di ricerca e sostituzione.
not2qubit

8

Per sostituire facilmente tutti 1con 10in a = [1,2,3,4,5,1,2,3,4,5,1]uno, è possibile utilizzare la seguente combinazione lambda + mappa a una riga e "Guarda, mamma, niente IF o FOR!" :

# 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))


Il metodo più lento di gran lunga. Stai chiamando un lambdaelemento su ogni elenco ...
Dawg,

4

Il seguente è un metodo molto diretto in 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

Questo metodo funziona. I commenti sono ben accetti Spero che sia d'aiuto :)

Anche provare a capire come Outis di e di damzam soluzioni di lavoro. Le compressioni dell'elenco e la funzione lambda sono strumenti utili.


4

Su elenchi lunghi e eventi rari è circa 3 volte più veloce utilizzando list.index()- rispetto ai metodi di iterazione a passaggio singolo presentati nelle altre risposte.

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

Questo è il metodo più veloce che ho trovato. Si prega di vedere i tempi nella mia risposta. Grande!
dawg,

3

So che questa è una domanda molto antica e ci sono una miriade di modi per farlo. Quello più semplice che ho trovato sta usando il numpypacchetto.

import numpy

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

3

Il mio caso d'uso stava sostituendo Nonecon un valore predefinito.

Ho cronometrato gli approcci a questo problema che sono stati presentati qui, incluso quello di @kxr - using str.count.

Codice di prova in 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)    

Ottengo:

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)

L'uso dell'interno str.indexè infatti più veloce di qualsiasi confronto manuale.

Non sapevo se l'eccezione nel test 4 sarebbe stata più laboriosa dell'uso str.count, la differenza sembra trascurabile.

Si noti che map()(test 6) restituisce un iteratore e non un elenco effettivo, quindi test 7.


2

Puoi semplicemente usare la comprensione dell'elenco in Python:

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

nel tuo caso, in cui desideri sostituire tutte le occorrenze di 1 con 10, lo snippet di codice sarà così:

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
Sebbene questo frammento di codice possa risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice. Cerca anche di non aggiungere il tuo codice a commenti esplicativi, ciò riduce la leggibilità sia del codice che delle spiegazioni!
Filnor,

-1

Trova e sostituisci un solo oggetto

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]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.