znajdowanie i zastępowanie elementów na liście

273

Muszę przeszukać listę i zastąpić wszystkie wystąpienia jednego elementu innym. Jak dotąd moje próby kodu nie prowadzą mnie nigdzie, jaki jest najlepszy sposób, aby to zrobić?

Załóżmy na przykład, że moja lista ma następujące liczby całkowite

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

i muszę zastąpić wszystkie wystąpienia liczby 1 wartością 10, więc potrzebuję wyniku

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

Dlatego moim celem jest zastąpienie wszystkich wystąpień liczby 1 liczbą 10.

James
źródło
11
A propos, po co to jest?
poza
Duplikat stackoverflow.com/q/1540049/819417
Cees Timmerman

Odpowiedzi:

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
źródło
15
To złe i bardzo nie pytonowe rozwiązanie. Zastanów się nad użyciem listy.
AdHominem
203
Jest to dobre, jeśli bardzo nie-pytonowe rozwiązanie. Zastanów się nad użyciem listy.
Jean-François Corbett
Zastanów się nad użyciem rozumienia listy, takiego jak @outis poniżej!
amc
6
Działa to jednak lepiej niż zrozumienie listy, prawda? Robi aktualizacje w miejscu zamiast generować nową listę.
neverendingqs
@neverendingqs: Nie. Narzut tłumacza dominuje nad operacją, a zrozumienie ma go mniej. Rozumienie działa nieco lepiej, szczególnie przy większym udziale elementów spełniających warunek wymiany. Mieć trochę czasu: ideone.com/ZrCy6z
użytkownik2357112 obsługuje Monikę
517

Spróbuj użyć listy i operatora trójskładnikowego .

>>> 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
źródło
9
Ale to się nie zmienia, aprawda? Myślę, że OP chciał asię zmienić
Dula
10
@Dula, możesz zrobić a = [4 jeśli x == 1 jeszcze x dla x w a], spowoduje to
Alekhya Vemavarapu
@Dula: pytanie jest niejasne, czy anależy mutować, ale (jak pokazuje Alekhya) proste jest zajmowanie się każdym z tych przypadków przy użyciu listy.
outis
34
Jeśli chcesz mutować a, powinieneś to zrobić a[:] = [4 if x==1 else x for x in a](zwróć uwagę na pełny wycinek listy). Samo a =utworzenie spowoduje utworzenie nowej listy az inną id()(tożsamością) od oryginalnej
Chris_Rands
39

Zrozumienie listy działa dobrze, a przechodzenie przez wyliczanie może zaoszczędzić trochę pamięci (b / c operacja jest zasadniczo wykonywana na miejscu).

Istnieje również programowanie funkcjonalne. Zobacz użycie mapy :

>>> 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
źródło
17
+1. Jest to bardzo złe lambdai mapsą uważane za niepythonic.
poza
4
Nie jestem pewien, czy lambda lub mapa są z natury niepytoniczne, ale zgodziłbym się, że zrozumienie listy jest czystsze i bardziej czytelne niż używanie ich obu w połączeniu.
damzam,
7
Sam nie uważam ich za pozbawione mitów, ale wielu tak, w tym Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). To jedna z tych sekciarskich rzeczy.
poza
35

Jeśli masz kilka wartości do zastąpienia, możesz również użyć słownika:

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
źródło
1
Czy to nie powoduje błędu, jeśli nnie można go znaleźć w dic?
Neil A.,
3
@ user2914540 Poprawiłem nieco twoją odpowiedź, więc działa, jeśli nnie zostanie znaleziona. Mam nadzieję, że nie masz nic przeciwko. Twoje try/exceptrozwiązanie nie było dobre.
jrjc
O tak, tak jest lepiej.
roipoussiere
1
@jrjc @roipoussiere do wymiany w miejscu, try-exceptjest co najmniej 50% szybszy! Spójrz na tę odpowiedź
lifebalance
4
if n in dic.keys()jest zły pod względem wydajności. Użyj if n in diclub dic.get(n,n)(wartość domyślna)
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
źródło
Metoda średnio szybka, ale bardzo rozsądna. Proszę zobaczyć czasy w mojej odpowiedzi.
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

Możesz użyć pętli for i lub while; jednak jeśli znasz wbudowaną funkcję wyliczania, zaleca się użycie wyliczenia. 1

Eimal Dorani
źródło
1
Jest to jedyny rozsądny (czytelny) sposób, aby to zrobić, gdy trzeba wykonać bardziej złożone operacje na elementach listy. Na przykład, jeśli każdy element listy jest długim ciągiem, który wymaga pewnego rodzaju wyszukiwania i zamiany.
not2qubit
8

Aby wymienić łatwo wszystko 1ze 10w a = [1,2,3,4,5,1,2,3,4,5,1]można użyć następującego jedna linia kombinację lambda + mapę i "Spójrz, mamo, nie ma IFS lub 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
źródło
Zdecydowanie najwolniejsza metoda. Dzwonisz do lambdakażdego elementu listy ...
dawg
4

Poniżej przedstawiono bardzo bezpośrednią metodę w Pythonie 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

Ta metoda działa. Komentarze są mile widziane. Mam nadzieję, że to pomoże :)

Spróbuj także zrozumieć, jak działają rozwiązania outis i damzam . Kompresje list i funkcja lambda są przydatnymi narzędziami.

Ananay Mital
źródło
3

Wiem, że to bardzo stare pytanie i istnieje mnóstwo sposobów, aby to zrobić. Znalazłem prostszy numpypakiet.

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
źródło
3

Mój przypadek użycia został zastąpiony Nonepewną wartością domyślną.

Podjęłam czasowe podejście do tego problemu, które zostały tutaj zaprezentowane, w tym ten autorstwa @kxr - using str.count.

Testuj kod w ipython z 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)    

Dostaję:

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)

Korzystanie z wewnętrznego str.indexjest w rzeczywistości szybsze niż jakiekolwiek ręczne porównanie.

Nie wiedziałem, czy wyjątek w teście 4 byłby bardziej pracochłonny niż używanie str.count, różnica wydaje się znikoma.

Zauważ, że map()(test 6) zwraca iterator, a nie rzeczywistą listę, dlatego test 7.

Sójka
źródło
3

Na długich listach i rzadkich zdarzeniach jest to około 3 razy szybsze użycie list.index()- w porównaniu do metod iteracji jednoetapowych przedstawionych w innych odpowiedziach.

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
źródło
To najszybsza metoda, jaką znalazłem. Proszę zobaczyć czasy w mojej odpowiedzi. Wspaniały!
dawg
2

Możesz po prostu użyć listy ze zrozumieniem w Pythonie:

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

w twoim przypadku, w którym chcesz zastąpić wszystkie wystąpienia 1 liczbą 10, fragment kodu będzie wyglądał następująco:

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
źródło
3
Ten fragment kodu może rozwiązać pytanie, ale wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie dla czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu. Staraj się również nie tłoczyć kodu objaśniającymi komentarzami, co zmniejsza czytelność zarówno kodu, jak i objaśnień!
Filnor
-1

Znajdź i zamień tylko jeden element

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
źródło