web-dev-qa-db-fra.com

Comment supprimer des éléments d'une liste lors d'une itération?

Je parcours une liste de n-uplets en Python et je tente de les supprimer s'ils répondent à certains critères. 

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

Que devrais-je utiliser à la place de code_to_remove_tup? Je n'arrive pas à comprendre comment supprimer l'article de cette façon.

785
lfaraone

Vous pouvez utiliser une compréhension de liste pour créer une nouvelle liste contenant uniquement les éléments que vous ne souhaitez pas supprimer:

somelist = [x for x in somelist if not determine(x)]

Ou, en attribuant à la tranche somelist[:], vous pouvez modifier la liste existante pour ne contenir que les éléments souhaités:

somelist[:] = [x for x in somelist if not determine(x)]

Cette approche pourrait être utile s'il existe d'autres références à somelist qui doivent refléter les modifications.

Au lieu d'une compréhension, vous pouvez également utiliser itertools. En Python 2:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

Ou en Python 3:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)
665
David Raznick

Les réponses suggérant des compréhensions de liste sont presque correctes - sauf qu'elles construisent une liste complètement nouvelle puis lui donnent le même nom que l'ancienne liste, elles ne modifient PAS l'ancienne liste en place. Ceci est différent de ce que vous feriez par suppression sélective, comme dans la suggestion de @ Lennart: c'est plus rapide, mais si vous accédez à votre liste via plusieurs références, vous ne remettez en place qu'une des références sans modifier l'objet de liste. lui-même peut conduire à des bugs subtils et désastreux.

Heureusement, il est extrêmement facile d'obtenir à la fois la vitesse de compréhension des listes ET la sémantique requise pour la modification sur place - il suffit de coder:

somelist[:] = [tup for tup in somelist if determine(tup)]

Notez la différence subtile avec d’autres réponses: celle-ci n’est PAS assignée à un nom de barre - c’est à une tranche de liste qui se trouve être la liste entière, remplaçant ainsi la liste contents _ ​​dans le même objet de liste Python}, plutôt que de simplement refaire une référence (d'un objet liste précédent à un nouvel objet liste) comme les autres réponses.

519
Alex Martelli

Vous devez d'abord en prendre une copie et l'itérer dessus, sinon l'itération échouera avec des résultats inattendus.

Par exemple (dépend de quel type de liste):

for tup in somelist[:]:
    etc....

Un exemple:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]
228
Lennart Regebro
for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

Vous devez revenir en arrière, sinon c'est un peu comme scier la branche d'arbre sur laquelle vous êtes assis :-)

Utilisateurs Python 2: remplacez range par xrange pour éviter de créer une liste codée en dur

98
John Machin

Votre meilleure approche pour un tel exemple serait une compréhension de la liste

somelist = [tup for tup in somelist if determine(tup)]

Dans les cas où vous faites quelque chose de plus complexe que d'appeler une fonction determine, je préfère créer une nouvelle liste et simplement l'ajouter au fur et à mesure. Par exemple

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

Copier la liste en utilisant remove peut donner à votre code un aspect un peu plus propre, comme décrit dans l’une des réponses ci-dessous. Vous ne devez absolument pas utiliser cette méthode pour les listes extrêmement volumineuses, car cela implique de copier d'abord la liste entière et d'effectuer une opération O(n)remove pour chaque élément supprimé, ce qui en fait un algorithme O(n^2).

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
46
Eli Courtwright

Le tutoriel officiel sur Python 2 4.2. "pour les déclarations" dit:

Si vous devez modifier la séquence sur laquelle vous effectuez une itération lorsque vous vous trouvez dans la boucle (par exemple, pour dupliquer les éléments sélectionnés), il est recommandé de faire d’abord une copie. Une itération sur une séquence ne crée pas implicitement une copie. La notation slice rend cela particulièrement pratique:

>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

qui est ce qui a été suggéré à: https://stackoverflow.com/a/1207427/895245

La Documentation Python 2 7.3. "The for statement" donne le même conseil:

Remarque: Il y a une subtilité lorsque la séquence est modifiée par la boucle (cela ne peut se produire que pour des séquences mutables, c'est-à-dire des listes). Un compteur interne est utilisé pour garder trace du prochain élément à utiliser, et il est incrémenté à chaque itération. Lorsque ce compteur a atteint la longueur de la séquence, la boucle se termine. Cela signifie que si la suite supprime l'élément en cours (ou un élément précédent) de la séquence, l'élément suivant sera ignoré (car il obtient l'index de l'élément en cours qui a déjà été traité). De même, si la suite insère un élément dans la séquence avant l'élément en cours, l'élément en cours sera traité à nouveau la prochaine fois dans la boucle. Cela peut conduire à de vilains bugs qui peuvent être évités en faisant une copie temporaire en utilisant une tranche de la séquence complète, par exemple:

for x in a[:]:
    if x < 0: a.remove(x)

Python pourrait-il mieux le faire?

Il semble que cette API Python particulière pourrait être améliorée. Comparez-le, par exemple, avec son homologue Java ListIterator , ce qui montre clairement que vous ne pouvez pas modifier une liste itérée à l'exception de l'itérateur lui-même, et vous permet de le faire sans copier la liste. Allez, Python!

Pour ceux qui aiment la programmation fonctionnelle:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

ou

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
36
Cide

Il peut être judicieux de créer simplement une nouvelle liste si l’élément de la liste actuelle répond aux critères souhaités. 

alors:

for item in originalList:
   if (item != badValue):
        newList.append(item)

et pour éviter de recoder le projet entier avec le nouveau nom de liste:

originalList[:] = newList

note, de la documentation Python: 

copie.copie (x) Retourne une copie superficielle de x.

copy.deepcopy (x) Renvoie une copie détaillée de x.

10
ntk4

J'avais besoin de faire cela avec une liste énorme, et dupliquer la liste semblait coûteuse, d'autant plus que dans mon cas, le nombre de suppressions serait peu comparé aux éléments restants. J'ai adopté cette approche de bas niveau.

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

Ce que je ne sais pas, c'est l'efficacité de quelques suppressions par rapport à la copie d'une liste volumineuse. Veuillez commenter si vous avez des idées.

10
Michael

Cette réponse a été écrite à l'origine en réponse à une question qui a depuis été marquée comme étant en double: Supprimer les coordonnées de la liste sur python

Il y a deux problèmes dans votre code:

1) Lorsque vous utilisez remove (), vous essayez de supprimer des entiers alors que vous devez supprimer un tuple.

2) La boucle for ignorera les éléments de votre liste.

Passons en revue ce qui se passe lorsque nous exécutons votre code:

>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
...   if a < 0 or b < 0:
...     L1.remove(a,b)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)

Le premier problème est que vous transmettez 'a' et 'b' à remove (), mais remove () n'accepte qu'un seul argument. Alors, comment pouvons-nous obtenir remove () pour fonctionner correctement avec votre liste? Nous devons déterminer quel est chaque élément de votre liste. Dans ce cas, chacun est un tuple. Pour voir cela, accédons à un élément de la liste (l'indexation commence à 0):

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'Tuple'>

Aha! Chaque élément de L1 est en fait un tuple. C’est donc ce que nous devons faire pour supprimer (). Les tuples en python sont très faciles, ils sont simplement fabriqués en plaçant les valeurs entre parenthèses. "a, b" n'est pas un tuple, mais "(a, b)" est un tuple. Nous modifions donc votre code et le relançons:

# The remove line now includes an extra "()" to make a Tuple out of "a,b"
L1.remove((a,b))

Ce code fonctionne sans erreur, mais regardons la liste qu'il affiche: 

L1 is now: [(1, 2), (5, 6), (1, -2)]

Pourquoi (1, -2) est-il toujours dans votre liste? Il s'avère que modifier la liste en itérant une boucle est une très mauvaise idée sans précaution particulière. La raison pour laquelle (1, -2) reste dans la liste est que l'emplacement de chaque élément de la liste a changé entre les itérations de la boucle for. Regardons ce qui se passe si nous alimentons le code ci-dessus avec une liste plus longue:

L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

Comme vous pouvez en déduire, chaque fois que l'instruction conditionnelle a la valeur true et qu'un élément de la liste est supprimé, la prochaine itération de la boucle ignorera l'évaluation du prochain élément de la liste car ses valeurs sont maintenant situées dans des index différents.

La solution la plus intuitive consiste à copier la liste, puis à parcourir la liste d'origine et à ne modifier que la copie. Vous pouvez essayer de le faire comme ceci:

L2 = L1
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)

Cependant, le résultat sera identique à avant:

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

En effet, lorsque nous avons créé L2, python n'a pas réellement créé de nouvel objet. Au lieu de cela, il a simplement référencé L2 sur le même objet que L1. Nous pouvons vérifier cela avec "est", ce qui est différent de simplement "égal" (==).

>>> L2=L1
>>> L1 is L2
True

Nous pouvons faire une copie conforme en utilisant copy.copy (). Alors tout fonctionne comme prévu:

import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

Enfin, il existe une solution plus propre que celle de faire une copie entièrement nouvelle de la L1. La fonction reverse ():

L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
    if a < 0 or b < 0 :
        L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

Malheureusement, je ne peux pas décrire correctement le fonctionnement de reverse (). Il retourne un objet 'listreverseiterator' lorsqu'une liste lui est transmise. Pour des raisons pratiques, vous pouvez penser que cela crée une copie inversée de son argument. C'est la solution que je recommande.

8
Cinghiale

Vous voudrez peut-être utiliser filter() disponible en tant que fonction intégrée.

Pour plus de détails voir ici

4
Xolve

Si vous voulez faire autre chose pendant l'itération, il peut être intéressant d'obtenir à la fois l'index (ce qui vous garantit de pouvoir le référencer, par exemple si vous avez une liste de dict) et le contenu réel de l'élément de liste.

inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]    
for idx, i in enumerate(inlist):
    do some stuff with i['field1']
    if somecondition:
        xlist.append(idx)
for i in reversed(xlist): del inlist[i]

enumerate vous donne accès à l'élément et à l'index à la fois. reversed est fait pour que les index que vous allez supprimer plus tard ne changent pas sur vous. 

4
fantabolous

Vous pouvez essayer de faire une boucle inversée, alors pour some_list vous ferez quelque chose comme:

list_len = len(some_list)
for i in range(list_len):
    reverse_i = list_len - 1 - i
    cur = some_list[reverse_i]

    # some logic with cur element

    if some_condition:
        some_list.pop(reverse_i)

De cette façon, l'index est aligné et ne souffre pas des mises à jour de la liste (que vous ouvriez ou non l'élément courant).

3
Queequeg

Une solution possible, utile si vous voulez non seulement supprimer certaines choses, mais aussi faire quelque chose avec tous les éléments dans une seule boucle:

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1
3
Alexey

J'avais besoin de faire quelque chose de similaire et dans mon cas, le problème était la mémoire - je devais fusionner plusieurs objets de jeu de données dans une liste, après avoir fait quelques choses avec eux, en tant que nouvel objet, et je devais me débarrasser de chaque entrée dans laquelle je fusais évitez de les dupliquer et d’exploser la mémoire. Dans mon cas, avoir les objets dans un dictionnaire au lieu d'une liste fonctionnait bien:

`` `

k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in Zip(k, v)}

print d
for i in range(5):
    print d[i]
    d.pop(i)
print d

`` `

2
rafa

TLDR:

J'ai écrit une bibliothèque qui vous permet de faire ceci:

from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)  
for tup in fSomeList:
    if determine(tup):
        # remove 'tup' without "breaking" the iteration
        fSomeList.remove(tup)
        # tup has also been removed from 'someList'
        # as well as 'fSomeList'

Il est préférable d'utiliser une autre méthode, si possible, qui ne nécessite pas de modifier votre itératif lors de son itération, mais pour certains algorithmes, cela peut ne pas être aussi simple. Et donc, si vous êtes sûr de vouloir vraiment le motif de code décrit dans la question initiale, c'est possible.

Devrait fonctionner sur toutes les séquences mutables et pas seulement sur les listes.


Réponse complète:

Edit: Le dernier exemple de code dans cette réponse donne un cas d'utilisation de pourquoi vous souhaiterez parfois modifier une liste à la place plutôt que d'utiliser une compréhension de liste. La première partie des réponses sert de didacticiel sur comment un tableau peut être modifié à la place.

La solution découle de this answer (pour une question connexe) de senderle. Ce qui explique comment l'index du tableau est mis à jour lors d'une itération dans une liste modifiée. La solution ci-dessous est conçue pour suivre correctement l'index de tableau même si la liste est modifiée.

Téléchargez fluidIter.py à partir de icihttps://github.com/alanbacon/FluidIterator, il ne s'agit que d'un seul fichier, vous n'avez donc pas besoin d'installer git. Il n'y a pas d'installation, vous devrez donc vous assurer que le fichier est bien dans le chemin python. Le code a été écrit pour Python 3 et n'a pas été testé sur Python 2.

from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]  
fluidL = FluidIterable(l)                       
for i in fluidL:
    print('initial state of list on this iteration: ' + str(fluidL)) 
    print('current iteration value: ' + str(i))
    print('popped value: ' + str(fluidL.pop(2)))
    print(' ')

print('Final List Value: ' + str(l))

Cela produira la sortie suivante:

initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2

initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3

initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4

initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5

initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6

initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7

initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8

Final List Value: [0, 1]

Ci-dessus, nous avons utilisé la méthode pop sur l'objet liste de fluides. D'autres méthodes itératives courantes sont également implémentées, telles que del fluidL[i], .remove, .insert, .append, .extend. La liste peut également être modifiée à l'aide de tranches (les méthodes sort et reverse ne sont pas implémentées).

La seule condition est que vous ne devez modifier la liste en place que si, à un moment quelconque, fluidL ou l ont été réaffectés à un autre objet de liste, le code ne fonctionnerait pas. L'objet fluidL d'origine serait toujours utilisé par la boucle for mais deviendrait hors de portée pour que nous puissions le modifier.

c'est à dire.

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

Si nous voulons accéder à la valeur d'index actuelle de la liste, nous ne pouvons pas utiliser énumérer, car cela ne compte que le nombre de fois que la boucle for a été exécutée. Au lieu de cela, nous allons utiliser l'objet itérateur directement.

fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
    print('enum: ', i)
    print('current val: ', v)
    print('current ind: ', fluidArrIter.currentIndex)
    print(fluidArr)
    fluidArr.insert(0,'a')
    print(' ')

print('Final List Value: ' + str(fluidArr))

Cela produira les éléments suivants:

enum:  0
current val:  0
current ind:  0
[0, 1, 2, 3]

enum:  1
current val:  1
current ind:  2
['a', 0, 1, 2, 3]

enum:  2
current val:  2
current ind:  4
['a', 'a', 0, 1, 2, 3]

enum:  3
current val:  3
current ind:  6
['a', 'a', 'a', 0, 1, 2, 3]

Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]

La classe FluidIterable fournit simplement un wrapper pour l'objet de liste d'origine. L'objet d'origine est accessible en tant que propriété de l'objet fluide, comme suit:

originalList = fluidArr.fixedIterable

Vous trouverez plus d'exemples/tests dans la section if __is "__main__": au bas de fluidIter.py. Celles-ci valent la peine d’être examinées car elles expliquent ce qui se passe dans diverses situations. Tels que: Remplacer une grande partie de la liste en utilisant une tranche. Ou en utilisant (et en modifiant) la même itérable dans les boucles imbriquées.

Comme je l’ai dit au début: c’est une solution complexe qui gênera la lisibilité de votre code et rendra le débogage plus difficile. Par conséquent, d’autres solutions, telles que la compréhension de la liste mentionnée dans réponse de David Raznick, devraient être envisagées en premier. Cela dit, j’ai trouvé des cas où cette classe m’était utile et était plus facile à utiliser que de garder une trace des indices d’éléments à supprimer.


Edit: Comme mentionné dans les commentaires, cette réponse ne présente pas vraiment un problème pour lequel cette approche fournit une solution. Je vais essayer de répondre à cela ici:

La compréhension de liste fournit un moyen de générer une nouvelle liste, mais ces approches ont tendance à examiner chaque élément séparément, plutôt que l’état actuel de la liste dans son ensemble.

c'est à dire.

newList = [i for i in oldList if testFunc(i)]

Mais que se passe-t-il si le résultat de testFunc dépend des éléments déjà ajoutés à newList? Ou les éléments encore dans oldList qui pourraient être ajoutés ensuite? Il y a peut-être encore un moyen d'utiliser une compréhension de liste, mais elle commencera à perdre de son élégance, et pour moi, il est plus facile de modifier une liste en place.

Le code ci-dessous est un exemple d'algorithme qui souffre du problème ci-dessus. L'algorithme réduira une liste de sorte qu'aucun élément ne soit un multiple d'un autre élément.

randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
    print(' ')
    print('outer val: ', i)
    innerIntsIter = fRandInts.__iter__()
    for j in innerIntsIter:
        innerIndex = innerIntsIter.currentIndex
        # skip the element that the outloop is currently on
        # because we don't want to test a value against itself
        if not innerIndex == fRandIntsIter.currentIndex:
            # if the test element, j, is a multiple 
            # of the reference element, i, then remove 'j'
            if j%i == 0:
                print('remove val: ', j)
                # remove element in place, without breaking the
                # iteration of either loop
                del fRandInts[innerIndex]
            # end if multiple, then remove
        # end if not the same value as outer loop
    # end inner loop
# end outerloop

print('')
print('final list: ', randInts)

La sortie et la liste réduite finale sont montrées ci-dessous

outer val:  70

outer val:  20
remove val:  80

outer val:  61

outer val:  54

outer val:  18
remove val:  54
remove val:  18

outer val:  7
remove val:  70

outer val:  55

outer val:  9
remove val:  18

final list:  [20, 61, 7, 55, 9]
2
Resonance

La méthode la plus efficace est la compréhension de liste, beaucoup de personnes exposent leur cas, bien sûr, c’est aussi un bon moyen d’obtenir une variable iterator à filter.

Filter reçoit une fonction et une séquence. Filter applique la fonction passée à chaque élément, puis décide de le conserver ou de le supprimer, selon que la valeur renvoyée par la fonction est True ou False.

Il y a un exemple (obtenir les cotes dans le tuple):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

Attention: vous ne pouvez pas non plus gérer les itérateurs. Les itérateurs sont parfois meilleurs que les séquences.

1
chseng

Les autres réponses sont correctes, c’est généralement une mauvaise idée de supprimer d’une liste que vous parcourez. L'itération inversée évite les pièges, mais il est beaucoup plus difficile de suivre le code qui le fait, il est donc préférable d'utiliser une liste de compréhension ou une variable filter.

Cependant, il existe un cas où il est prudent de supprimer des éléments d'une séquence que vous effectuez une itération: si vous ne supprimez qu'un élément pendant que vous effectuez une itération. Ceci peut être assuré en utilisant return ou break. Par exemple:

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

C'est souvent plus facile à comprendre qu'une compréhension de liste lorsque vous effectuez des opérations avec des effets secondaires sur le premier élément d'une liste qui remplit certaines conditions, puis que vous supprimez cet élément de la liste immédiatement après.

1
Beefster

La plupart des réponses ici vous demandent de créer une copie de la liste. J'ai eu un cas d'utilisation où la liste était assez longue (110K éléments) et il était plus intelligent de continuer à réduire la liste à la place.

Tout d’abord, vous devrez remplacer la boucle foreach par la boucle while ,

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

La valeur de i n'est pas modifiée dans le bloc if car vous voudrez obtenir la valeur du nouvel élément FROM THE SAME INDEX, une fois que l'ancien article est supprimé.

1
Mujeeb

Je peux penser à trois approches pour résoudre votre problème. Par exemple, je vais créer une liste aléatoire de tuples somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)]. La condition que je choisis est sum of elements of a Tuple = 15. Dans la liste finale, nous n’aurons que les n-uplets dont la somme n’est pas égale à 15. 

Ce que j'ai choisi est un exemple choisi au hasard. N'hésitez pas à changer la liste de tuples et la condition que j'ai choisie. 

Méthode 1.> Utilisez le cadre que vous avez suggéré (où l'on remplit un code dans une boucle for). J'utilise un petit code avec del pour supprimer un tuple qui remplit ladite condition. Cependant, cette méthode ratera un tuple (qui remplit ladite condition) si deux n-uplets placés consécutivement remplissent la condition donnée. 

for tup in somelist:
    if ( sum(tup)==15 ): 
        del somelist[somelist.index(tup)]

print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]

Méthode 2.> Construit une nouvelle liste qui contient des éléments (tuples) pour lesquels la condition donnée n'est pas remplie (c'est la même chose que supprimer des éléments de la liste lorsque la condition donnée est remplie). Voici le code pour cela:

newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]

print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

Méthode 3.> Trouve les index pour lesquels la condition donnée est remplie, puis utilise remove des éléments (tuples) correspondant à ces index. Voici le code pour cela.

indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]

print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

La méthode 1 et la méthode 2 sont plus rapides que la méthode 3 . Method2 et method3 sont plus efficaces que method1. Je préfère method2 . Pour l'exemple ci-dessus, time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7

1
Siddharth Satpathy

pour la boucle sera itérer à travers l'index ..

considérez que vous avez une liste,

[5, 7, 13, 29, 65, 91]

vous utilisez une variable de liste appelée lis. et vous utilisez même pour enlever ..

votre variable

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

lors de la 5ème itération,

votre numéro 35 n'était pas un nombre premier, vous l'avez donc retiré de la liste.

lis.remove(y)

et ensuite valeur suivante (65) passer à l'index précédent.

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

donc 4ème itération pointeur déplacé sur 5ème ..

c’est la raison pour laquelle votre boucle ne couvre pas 65 depuis sa migration dans l’index précédent.

vous ne devez donc pas référencer la liste dans une autre variable qui fait toujours référence à l’original au lieu de la copie.

ite = lis #dont do it will reference instead copy

donc copie de la liste en utilisant list[::]

maintenant vous allez donner,

[5, 7, 13, 29]

Le problème est que vous avez supprimé une valeur d'une liste lors de l'itération, puis votre index de liste sera réduit.

afin que vous puissiez essayer la compréhension à la place.

qui supporte tous les types itérables, list, tuple, dict, string, etc.

0
Silent Spectator

Pour tout ce qui a le potentiel d’être vraiment gros, j’utilise ce qui suit. 

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

Cela devrait être beaucoup plus rapide que toute autre chose. 

0
CENTURION

mettre en place une liste de nombres et que vous voulez supprimer tous les non divisibles par 3,

list_number =[i for i in range(100)]

en utilisant list comprehension, cela créera une nouvelle liste et créera un nouvel espace mémoire

new_list =[i for i in list_number if i%3!=0]

en utilisant la fonction lambda filter, cela créera une nouvelle liste et utilisera de l’espace mémoire

new_list = list(filter(lambda x:x%3!=0, list_number))

sans utiliser l'espace mémoire pour la nouvelle liste et modifier la liste existante

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)
0
prashant rana

Dans certaines situations, lorsque vous ne vous contentez pas de filtrer un élément à la fois, vous souhaitez que votre itération change en même temps.

Voici un exemple où la copie préalable de la liste est incorrecte, l’itération inversée est impossible et une compréhension de la liste n’est pas non plus une option.

""" Sieve of Eratosthenes """

def generate_primes(n):
    """ Generates all primes less than n. """
    primes = list(range(2,n))
    idx = 0
    while idx < len(primes):
        p = primes[idx]
        for multiple in range(p+p, n, p):
            try:
                primes.remove(multiple)
            except ValueError:
                pass #EAFP
        idx += 1
        yield p
0
CodeKid

Si vous souhaitez utiliser la nouvelle liste ultérieurement, vous pouvez simplement définir l'emblème sur Aucun, puis le juger dans la boucle ultérieure, comme ceci

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

De cette façon, vous n'avez pas besoin de copier la liste et elle est plus facile à comprendre.

0
john zhang