Suchen und Ersetzen von Elementen in einer Liste


273

Ich muss eine Liste durchsuchen und alle Vorkommen eines Elements durch ein anderes ersetzen. Bisher bringen mich meine Codeversuche nicht weiter. Was ist der beste Weg, dies zu tun?

Angenommen, meine Liste enthält die folgenden Ganzzahlen

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

und ich muss alle Vorkommen der Zahl 1 durch den Wert 10 ersetzen, damit die Ausgabe, die ich brauche, ist

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

Mein Ziel ist es daher, alle Instanzen der Nummer 1 durch die Nummer 10 zu ersetzen.


11
Wofür ist das übrigens?
Outis

Antworten:


249
>>> 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
Dies ist eine schlechte und sehr unpythonische Lösung. Erwägen Sie die Verwendung des Listenverständnisses.
AdHominem

201
Dies ist eine gute, wenn auch sehr unpythonische Lösung. Erwägen Sie die Verwendung des Listenverständnisses.
Jean-François Corbett

Erwägen Sie die Verwendung des Listenverständnisses, wie es von @outis unten durchgeführt wird!
Amc

6
Dies ist besser als das Listenverständnis, nicht wahr? Es werden direkte Aktualisierungen durchgeführt, anstatt eine neue Liste zu erstellen.
Neverendingqs

@neverendingqs: Nein. Der Interpreter-Overhead dominiert die Operation, und das Verständnis hat weniger davon. Das Verständnis ist etwas besser, insbesondere wenn ein höherer Anteil der Elemente die Ersetzungsbedingung erfüllt. Haben Sie einige Timings: ideone.com/ZrCy6z
user2357112 unterstützt Monica

516

Versuchen Sie es mit einem Listenverständnis und dem ternären Operator .

>>> 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
Das ändert sich aber nicht, aoder? Ich denke, OP wollte asich ändern
Dula

10
@Dula Sie können a = [4, wenn x == 1 sonst x für x in a], dies wird a
Alekhya Vemavarapu

@Dula: Die Frage ist vage, ob amutiert werden soll, aber (wie Alekhya zeigt) ist es trivial, beide Fälle zu behandeln, wenn ein Listenverständnis verwendet wird.
Outis

34
Wenn Sie mutieren möchten, asollten Sie dies tun a[:] = [4 if x==1 else x for x in a](beachten Sie das vollständige Listen-Slice). Wenn Sie dies tun, a =wird eine neue Liste amit einer anderen id()(Identität) als der ursprünglichen erstellt
Chris_Rands

39

Das Listenverständnis funktioniert gut, und das Durchlaufen mit enumerate kann Ihnen Speicherplatz sparen (b / c wird die Operation im Wesentlichen an Ort und Stelle ausgeführt).

Es gibt auch funktionale Programmierung. Siehe Verwendung der Karte :

>>> 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 ist schade lambdaund mapgelten als unpythonisch.
Outis

4
Ich bin mir nicht sicher, ob Lambda oder Map von Natur aus unpythonisch ist, aber ich stimme zu, dass ein Listenverständnis sauberer und lesbarer ist als die Verwendung der beiden zusammen.
Damzam

7
Ich halte sie selbst nicht für unpythonisch, aber viele, einschließlich Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). Es ist eines dieser sektiererischen Dinge.
Outis

35

Wenn Sie mehrere Werte ersetzen müssen, können Sie auch ein Wörterbuch verwenden:

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
Wirft dies nicht einen Fehler, wenn nes nicht gefunden wird dic?
Neil A.

3
@ user2914540 Ich habe Ihre Antwort ein wenig verbessert, damit sie funktioniert, wenn sie nnicht gefunden wird. Ich hoffe es macht dir nichts aus. Ihre try/exceptLösung war nicht gut.
Jrjc

Oh ja, das ist besser.
Roipoussiere

1
@jrjc @roipoussiere für In-Place-Ersatz, das try-exceptist mindestens 50% schneller!
Werfen

4
if n in dic.keys()ist schlecht in Bezug auf die Leistung. Verwenden Sie if n in dicoder dic.get(n,n)(Standardwert)
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]
>>> 

Mittelschnelle aber sehr vernünftige Methode. Bitte beachten Sie die Zeiten in meiner Antwort.
Morgengrauen

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

Sie können eine for- und / oder while-Schleife verwenden. Wenn Sie jedoch die integrierte Aufzählungsfunktion kennen, wird empfohlen, Aufzählung zu verwenden. 1


1
Dies ist die einzig vernünftige (lesbare) Möglichkeit, dies zu tun, wenn Sie komplexere Operationen an den Listenelementen ausführen müssen. Zum Beispiel, wenn jedes Listenelement eine lange Zeichenfolge ist, die gesucht und ersetzt werden muss.
not2qubit

8

So ersetzen Sie einfach alle 1mit 10in a = [1,2,3,4,5,1,2,3,4,5,1]einer der folgenden einzeiligen Lambda + Karte Kombination verwenden könnte, und ‚Schauen Sie , Ma, keine IFs oder 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))


Mit Abstand langsamste Methode. Sie rufen lambdaauf jedem Listenelement ein ...
dawg

4

Das Folgende ist eine sehr direkte Methode 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

Diese Methode funktioniert. Kommentare sind willkommen. Ich hoffe es hilft :)

Versuchen Sie auch zu verstehen, wie die Lösungen von outis und damzam funktionieren. Listenkomprimierungen und Lambda-Funktionen sind nützliche Werkzeuge.


3

Ich weiß, dass dies eine sehr alte Frage ist und es gibt unzählige Möglichkeiten, dies zu tun. Das einfachere, das ich gefunden habe, ist die Verwendung eines numpyPakets.

import numpy

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

3

Mein Anwendungsfall wurde ersetzt None einen Standardwert ersetzt.

Ich habe zeitgesteuerte Ansätze für dieses Problem, die hier vorgestellt wurden, einschließlich der von @kxr - using str.count.

Testcode in ipython mit 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)    

Ich bekomme:

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)

Die Verwendung des internen str.indexist in der Tat schneller als jeder manuelle Vergleich.

Ich wusste nicht, ob die Ausnahme in Test 4 mühsamer sein würde als die Verwendung str.count, der Unterschied scheint vernachlässigbar.

Beachten Sie, dass map()(Test 6) einen Iterator und keine tatsächliche Liste zurückgibt, also Test 7.


3

Bei langen Listen und seltenen Vorkommen ist die Verwendung etwa dreimal schneller list.index()- im Vergleich zu Einzelschritt-Iterationsmethoden, die in den anderen Antworten vorgestellt werden.

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

Dies ist die schnellste Methode, die ich gefunden habe. Bitte beachten Sie die Zeiten in meiner Antwort. Großartig!
Morgengrauen

2

Sie können das Listenverständnis einfach in Python verwenden:

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

In Ihrem Fall, in dem Sie alle Vorkommen von 1 durch 10 ersetzen möchten, sieht das Code-Snippet folgendermaßen aus:

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
Während dieses Code-Snippet die Frage lösen kann, hilft eine Erklärung wirklich dabei, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen. Bitte versuchen Sie auch, Ihren Code nicht mit erklärenden Kommentaren zu überfüllen. Dies verringert die Lesbarkeit sowohl des Codes als auch der Erklärungen!
Filnor

-1

Suchen und ersetzen Sie nur einen Artikel

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]
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.