Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

del, remove, autre ?

4 réponses
Avatar
PIGUET Bruno
Bonjour,

Je débute en Python, je cherche à supprimer des chaînes
(correspondant à un certain critère) dans une liste, et je ne suis pas
trop satisfait du code auquel je suis parvenu.
Exemple simple:
l=["total 3", "taratata titi toto"]
for line in l:
sl = line.split()
if len(sl) == 2 and sl[0] == "total" :
l.remove(line)

Auriez-vous une piste vers quelque chose de plus élégant ?

Merci,

Bruno.

4 réponses

Avatar
Bruno Desthuilliers
Bonjour,

Je débute en Python, je cherche à supprimer des chaînes (correspondant
à un certain critère) dans une liste, et je ne suis pas trop satisfait
du code auquel je suis parvenu.
Exemple simple:
l=["total 3", "taratata titi toto"]
for line in l:
sl = line.split()
if len(sl) == 2 and sl[0] == "total" :
l.remove(line)


Modifier la liste sur laquelle on itère est généralement assez risqué:

l = range(10)
for n, i in enumerate(l):
... print n, i



... if i % 2 : del l[i]
...
0 0
1 1
2 3
3 5
4 6
5 8
6 9
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
IndexError: list assignment index out of range




Auriez-vous une piste vers quelque chose de plus élégant ?


Tu ne nous dit pas grand chose sur le contexte...

A tu vraiment besoin de modifier la liste "en place", ou la création
d'une nouvelle liste est-elle ok ?

La condition est-elle toujours la même est-elle appelée à changer ?

En tout état de cause, les solutions "canoniques" se basent généralement
sur la création d'une nouvelle liste "filtrée" (pour éviter les effets
de bords indésirables constatés ci dessus), en utilisant soit la
fonction filter soit une liste en intention.

# definition d'un prédicat pour déterminer si on doit garder la ligne
# ou la supprimer:

def keep(line):
parts = line.split()
if len(parts) == 2 and parts[0] == "total":
return False
return True

source = ["total 3", "taratata titi toto"]

# par filtrage:
dest = filter(keep, source)

# avec une liste en intention:
dest = [line for line in source if keep(line)]


Après, on peut varier les approches pour le prédicat, par exemple avec
une regexp:

import re
test_exp = re.compile(r'^total d+$')

dest = filter(lambda line: test_exp.match(line), source)

etc...

Si la liste est partagée et que tu a vraiment besoin de modifier
l'original, tu peux le faire ainsi:

dest = [line for line in source if keep(line)]
source[:] = dest

HTH



Avatar
Pierre Maurette
Bonjour,

Je débute en Python, je cherche à supprimer des chaînes (correspondant à
un certain critère) dans une liste, et je ne suis pas trop satisfait du code
auquel je suis parvenu.
Exemple simple:
l=["total 3", "taratata titi toto"]
for line in l:
sl = line.split()
if len(sl) == 2 and sl[0] == "total" :
l.remove(line)

Auriez-vous une piste vers quelque chose de plus élégant ?


Elégant, je ne sais pas. Quelques propositions:

l=["total 3", "taratata titi toto"]

[l.remove(s) for s in l if s.split()[0] == 'total' and len(s.split())
== 2]
print l

l=["total 3", "taratata titi toto"]

print [s for s in l if s.split()[0] != 'total' or len(s.split()) != 2]

print filter(lambda s:s.split()[0] != 'total' or len(s.split()) != 2,
l)

def test(s):
dummi = s.split()
return len(dummi) != 2 or dummi[0] != "total"

[l.remove(s) for s in l if not test(s)]
print l

l=["total 3", "taratata titi toto"]

print [s for s in l if test(s)]

print filter(test, l)

Dans la première série, on appelle deux fois split() par itération.
Enfin, on l'appelle deux fois si le premier appel ne permet pas de
conclure (évaluation économique des booléens), il suffit peut-être de
choisir l'ordre selon le contexte.

--
Pierre Maurette

Avatar
Bruno Piguet


Modifier la liste sur laquelle on itère est généralement assez risqué:


C'était bien ça que je voulais éviter. Même sans l'exemple fourni
gentiment, je sentais bien le danger.


En tout état de cause, les solutions "canoniques" se basent généralement
sur la création d'une nouvelle liste "filtrée" (pour éviter les effets
de bords indésirables constatés ci dessus), en utilisant soit la
fonction filter soit une liste en intention.


Bon sang mais c'est bien sûr ! filter() ! c'est dans toutes les docs !

En fait, j'étais parti à la recherche d'un truc du genre
dest = source [where keep(source)])
C'est une construction qui existe dans d'autre langages... et qui
m'avait fait perdre de vue les choses simples et directes.

Merci.

Bruno.

Avatar
Bruno Desthuilliers


Modifier la liste sur laquelle on itère est généralement assez risqué:


C'était bien ça que je voulais éviter. Même sans l'exemple fourni
gentiment, je sentais bien le danger.


En tout état de cause, les solutions "canoniques" se basent
généralement sur la création d'une nouvelle liste "filtrée" (pour
éviter les effets de bords indésirables constatés ci dessus), en
utilisant soit la fonction filter soit une liste en intention.


Bon sang mais c'est bien sûr ! filter() ! c'est dans toutes les docs !

En fait, j'étais parti à la recherche d'un truc du genre
dest = source [where keep(source)])

C'est une construction qui existe dans d'autre langages... et qui
m'avait fait perdre de vue les choses simples et directes.


En Python, c'est:

dest = [item for item in source if keep(item)]

(construction essentiellement pompée à Haskell...)