del, remove, autre ?

Le
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.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Bruno Desthuilliers
Le #1993021
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



Pierre Maurette
Le #1993011
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

Bruno Piguet
Le #1995841


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.

Bruno Desthuilliers
Le #2046121


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...)


Publicité
Poster une réponse
Anonyme