Question

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 dois-je utiliser à la place de code_à_remove_tup ? Je n'arrive pas à comprendre comment supprimer l'élément de cette manière.

Était-ce utile?

La solution

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 à liste somaliste 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)

Autres conseils

Les réponses suggérant des interprétations de liste sont presque correctes, à la différence qu’elles construisent une liste complètement nouvelle et lui donnent le même nom que l’ancienne liste car elles ne modifient PAS l’ancienne liste en place. C’est différent de ce que vous feriez de la suppression sélective, comme dans la suggestion de Lennart - c'est plus rapide, mais si votre La liste est accessible via plusieurs références. Le fait de ne pas réinstaller une des références et de NE PAS modifier l’objet List lui-même peut conduire à des bogues subtils et désastreux.

Heureusement, il est extrêmement facile de connaître à 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 affectée à un nom de barre - c’est à une tranche de liste qui se trouve être la liste entière, remplaçant ainsi la liste contenu dans le même objet de liste Python , plutôt que de simplement redéfinir une référence (d'un objet de liste précédent à un nouvel objet de liste) comme les autres réponses.

Vous devez d'abord créer une copie de la liste et la parcourir, sinon cette itération échouera avec des résultats inattendus.

Par exemple (dépend du 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
[]
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 de Python 2: remplacez la plage par xrange pour éviter de créer une liste codée en dur

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 Determiner , 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

La copie de la liste à l'aide de remove peut donner à votre code un aspect un peu plus propre, comme décrit dans l'une des réponses ci-dessous. Ne le faites certainement pas pour les listes extrêmement volumineuses, car cela implique tout d'abord de copier la liste entière, puis d'effectuer une opération O (n) remove pour chaque élément à supprimer, 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)

Didacticiel officiel de Python 2 4.2. "pour les déclarations"

https://docs.python.org/2/tutorial /controlflow.html#for-statements

Cette partie de la documentation indique clairement que:

  • vous devez faire une copie de la liste itérée pour la modifier
  • une façon de le faire est d'utiliser la notation de tranche [:]
  

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

>>> words = ['cat', 'window', 'defenestrate']
>>> 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']

Documentation Python 2 7.3. "Le for statement"

https://docs.python.org/2/reference/compound_stmts .html # pour

Cette partie de la documentation indique à nouveau que vous devez faire une copie et donne un exemple de suppression:

  

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 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 actuel (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 mauvais 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)

Cependant, je ne suis pas d'accord avec cette implémentation, car .remove () doit parcourir la liste entière pour trouver la valeur.

À la place, soit:

En général, vous souhaitez simplement utiliser l'option .append () plus rapide par défaut, à moins que la mémoire ne soit un gros problème.

Python pourrait-il mieux faire cela?

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

La raison sous-jacente est peut-être que les listes Python sont supposées être des tableaux dynamiques, ce qui signifie que tout type de suppression sera de toute façon peu efficace, alors que Java a une meilleure hiérarchie d'interface avec ArrayList et LinkedList implémentations de ListIterator .

Il ne semble pas exister de type de liste liée explicite dans la bibliothèque stdlib Python: Liste chaînée 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))

Il peut être judicieux de simplement créer 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, d'après la documentation Python:

  

copy.copy (x)   Renvoyer une copie superficielle de x.

     

copy.deepcopy (x)   Renvoyer une copie complète de x.

J'avais besoin de faire cela avec une longue liste, 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é avec laquelle deux suppressions sont comparées à la copie d'une longue liste. Veuillez commenter si vous avez des idées.

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 d'une liste sur python

Votre code pose deux problèmes:

1) Lorsque vous utilisez remove (), vous essayez de supprimer les 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 réexécutons:

# 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) figure-t-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 ce résultat, 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 désormais situées à l'emplacement suivant. différents indices.

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, la sortie sera identique à auparavant:

'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 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 "est égal à". (==).

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

Nous pouvons faire une copie conforme en utilisant copy.copy (). Ensuite, 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 la création d’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.

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

énumérer vous permet d'accéder à l'élément et à l'index en une fois. reverse permet d'éviter que les index que vous supprimez ultérieurement ne changent.

Vous pouvez utiliser filter () en tant que fonction intégrée.

Pour plus de détails, cliquez ici

.

Vous pouvez essayer de faire une boucle en sens inverse afin que vous puissiez faire 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)

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

Une solution possible, utile si vous souhaitez non seulement supprimer certaines choses, mais également faire quelque chose avec tous les éléments d'une même 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

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 devez 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 DEPUIS LE MÊME INDEX, une fois que l'ancien élément est supprimé.

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 opérations avec eux, en tant que nouvel objet, et je devais me débarrasser de chaque entrée. fusionnait pour éviter 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

`` `

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, si possible, une autre méthode qui ne nécessite pas de modifier votre itérable, 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:

Modifier: le dernier exemple de code dans cette réponse donne un exemple d'utilisation de pourquoi vous pourriez parfois vouloir 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 la réponse (pour une question connexe) de l'expéditeur. 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 ici https: / /github.com/alanbacon/FluidIterator , il s’agit simplement d’un fichier, il n’est donc pas nécessaire d’installer git. Il n'y a pas d'installation, vous devez 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))

Ceci 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]

Nous avons utilisé ci-dessus la méthode pop sur l'objet de 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, à tout moment, fluidL ou l était réaffecté à un autre objet de liste, le code ne fonctionnerait pas. . L’objet original fluidL 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 utiliserons 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))

Ceci produira les informations suivantes:

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 uniquement 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 d'autres exemples / tests dans la section si __name__ est "__ 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 compliquée qui gênera la lisibilité de votre code et rendra le débogage plus difficile. Par conséquent, d’autres solutions telles que la liste de définitions mentionnée dans la réponse de David Raznick doivent être envisagées en premier lieu. Cela dit, j’ai trouvé des cas où cette classe m’était utile et plus facile à utiliser que de garder une trace des indices des éléments à supprimer.

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

La compréhension des listes fournit un moyen de générer une nouvelle liste, mais ces approches tendent à examiner chaque élément de manière isolée 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 déjà des éléments 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)

Le résultat et la liste réduite finale sont affichés 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]

Les autres réponses sont exactes, 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 un filtre .

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 un return ou une pause . 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 la 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.

La méthode la plus efficace est la compréhension de liste, beaucoup de gens exposent leur cas, bien sûr, c’est aussi un bon moyen d’obtenir un itérateur via filtre .

  

Filtre reçoit une fonction et une séquence. Filtre applique la fonction transmise à 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 (obtenez la cote 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.

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 la somme d'éléments d'un 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 à modifier la liste des n-uplets et la condition que j'ai choisies.

Méthode 1. > Utilisez le cadre que vous avez suggéré (dans lequel 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 satisfait à la condition précitée) 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. > Construisez une nouvelle liste contenant des éléments (tuples) pour lesquels la condition donnée n'est pas remplie (c'est la même chose que de 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. > Recherchez les index pour lesquels la condition donnée est remplie, puis utilisez les éléments de suppression (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)]

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

La boucle for sera itérée à 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 la même chose 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 supprimé de la liste.

lis.remove(y)

puis valeur suivante (65) permettent de passer à l'index précédent.

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

le pointeur de la 4ème itération est donc passé à la 5ème ..

C’est pour cela que votre boucle ne couvre pas 65 depuis son passage dans l’index précédent.

donc vous ne devriez 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 faites une 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 itérables comme list, tuple, dict, string etc

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.

Dans certaines situations, lorsque vous ne vous contentez pas de filtrer une liste à 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 la 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

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 suivante, 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.

mettre en évidence 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 compréhension de liste , 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]

utilisant la fonction filtre lambda , 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 d'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)

Désormais, vous souhaitez créer une copie de la liste afin de pouvoir l'utiliser comme référence lorsque vous effectuez une itération et supprimez des n-uplets de cette liste qui répondent à certains critères.

Ensuite, cela dépend du type de liste que vous voulez pour la sortie, qu'il s'agisse d'une liste des n-uplets supprimés ou d'une liste des n-uplets qui ne sont pas supprimés.

Comme David l'a souligné, je recommande la compréhension de la liste pour conserver les éléments que vous ne souhaitez pas supprimer.

somelist = [x for x in somelist if not determine(x)]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top