rechercher et remplacer des éléments dans une liste

273

Je dois parcourir une liste et remplacer toutes les occurrences d'un élément par un autre. Jusqu'à présent, mes tentatives de code ne me mènent nulle part, quelle est la meilleure façon de procéder?

Par exemple, supposons que ma liste ait les entiers suivants

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

et je dois remplacer toutes les occurrences du nombre 1 par la valeur 10 de sorte que la sortie dont j'ai besoin est

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

Mon objectif est donc de remplacer toutes les instances du nombre 1 par le nombre 10.

James
la source
11
A quoi ça sert, au fait?
2010
Duplicate of stackoverflow.com/q/1540049/819417
Cees Timmerman

Réponses:

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
la source
15
C'est une mauvaise solution et très peu pythonique. Pensez à utiliser la compréhension de la liste.
AdHominem
205
Ceci est une solution fine mais très peu pythonique. Pensez à utiliser la compréhension de la liste.
Jean-François Corbett
Pensez à utiliser la compréhension de la liste, comme le fait @outis ci-dessous!
amc
6
Cela fonctionne mieux que la compréhension de la liste, n'est-ce pas? Il fait des mises à jour sur place au lieu de générer une nouvelle liste.
neverendingqs
@neverendingqs: Non. Les frais généraux de l'interprète dominent l'opération, et la compréhension en a moins. La compréhension fonctionne légèrement mieux, surtout avec une proportion plus élevée d'éléments passant la condition de remplacement. Ayez quelques synchronisations: ideone.com/ZrCy6z
user2357112 prend en charge Monica
519

Essayez d'utiliser une compréhension de liste et l' opérateur ternaire .

>>> 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
la source
9
Mais cela ne change pas, anon? Je pense que OP voulait achanger
Dula
10
@Dula vous pouvez faire a = [4 si x == 1 sinon x pour x dans a], cela affectera un
Alekhya Vemavarapu
@Dula: la question est vague de savoir s'il afaut muter, mais (comme le montre Alekhya), il est trivial de gérer l'un ou l'autre cas lors de l'utilisation d'une liste de compréhension.
Outis
34
Si vous voulez muter, avous devez le faire a[:] = [4 if x==1 else x for x in a](notez la tranche de la liste complète). Le simple fait de a =créer une nouvelle liste aavec une id()(identité) différente de l'original
Chris_Rands
39

La compréhension de la liste fonctionne bien, et parcourir avec énumérer peut vous faire économiser de la mémoire (car l'opération est essentiellement effectuée sur place).

Il y a aussi une programmation fonctionnelle. Voir l'utilisation de la carte :

>>> 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
la source
17
+1. C'est dommage lambdaet mapsont considérés comme non pythoniques.
2010 à 0h02
4
Je ne suis pas sûr que lambda ou map soit intrinsèquement non pythonique, mais je conviens qu'une compréhension de la liste est plus propre et plus lisible que d'utiliser les deux conjointement.
damzam
7
Je ne les considère pas comme impythoniques moi-même, mais beaucoup le font, y compris Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). C'est une de ces choses sectaires.
2010
36

Si vous avez plusieurs valeurs à remplacer, vous pouvez également utiliser un dictionnaire:

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
la source
1
Cela ne génère-t-il pas une erreur s'il nn'est pas trouvé dans dic?
Neil A.
3
@ user2914540 J'ai un peu amélioré votre réponse pour qu'elle fonctionne si elle nn'est pas trouvée. J'espère que ça ne vous dérange pas. Votre try/exceptsolution n'était pas bonne.
jrjc
Oh oui, c'est mieux.
roipoussiere
1
@jrjc @roipoussiere pour les remplacements sur place, try-exceptc'est au moins 50% plus rapide! Jetez un oeil à cette réponse
lifebalance
4
if n in dic.keys()est mauvais en termes de performances. Utiliser if n in dicou dic.get(n,n)(valeur par défaut)
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
la source
Méthode moyenne rapide mais très sensible. Veuillez voir les horaires dans ma réponse.
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

Vous pouvez utiliser une boucle for et or while; cependant, si vous connaissez la fonction Enumerate intégrée, il est recommandé d'utiliser Enumerate. 1

Eimal Dorani
la source
1
C'est la seule façon sensée (lisible) de le faire lorsque vous devez effectuer des opérations plus complexes sur les éléments de la liste. Par exemple, si chaque élément de la liste est une longue chaîne qui nécessite une sorte de recherche et de remplacement.
not2qubit
8

Pour remplacer facilement tout 1avec 10dans a = [1,2,3,4,5,1,2,3,4,5,1]on pourrait utiliser ce qui suit une ligne lambda + combinaison de la carte, et 'Look, Ma, pas ou Fors FI! :

# 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
la source
Méthode la plus lente de loin. Vous appelez un lambdaélément sur chaque liste ...
dawg
4

Ce qui suit est une méthode très directe 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

Cette méthode fonctionne. Les commentaires sont les bienvenus. J'espère que ça aide :)

Essayez également de comprendre le fonctionnement des solutions d' Outis et de Damzam . Les compressions de liste et la fonction lambda sont des outils utiles.

Ananay Mital
la source
4

Sur les longues listes et les occurrences rares, il est environ 3 fois plus rapide à utiliser list.index()- par rapport aux méthodes d'itération en une seule étape présentées dans les autres réponses.

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
la source
C'est la méthode la plus rapide que j'ai trouvée. Veuillez voir les horaires dans ma réponse. Génial!
Dawg
3

Je sais que c'est une très vieille question et il existe une multitude de façons de le faire. Le plus simple que j'ai trouvé utilise numpypackage.

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
la source
3

Mon cas d'utilisation remplaçait Nonepar une valeur par défaut.

J'ai chronométré les approches de ce problème qui ont été présentées ici, y compris celle de @kxr - using str.count.

Testez le code en ipython avec 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)    

Je reçois:

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'utilisation de l'interne str.indexest en fait plus rapide que toute comparaison manuelle.

Je ne savais pas si l'exception du test 4 serait plus laborieuse que l'utilisation str.count, la différence semble négligeable.

Notez que map()(test 6) renvoie un itérateur et non une liste réelle, donc test 7.

Geai
la source
2

Vous pouvez simplement utiliser la compréhension de liste en python:

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

pour votre cas, où vous souhaitez remplacer toutes les occurrences de 1 par 10, l'extrait de code sera comme ceci:

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
la source
3
Bien que cet extrait de code puisse résoudre la question, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question pour les lecteurs à l'avenir, et ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. Essayez également de ne pas surcharger votre code avec des commentaires explicatifs, cela réduit la lisibilité du code et des explications!
Filnor
-1

Trouver et remplacer un seul article

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
la source