Supprimer valeur dict avec boucle for python

Résolu/Fermé
Isfy_18 - Modifié le 9 déc. 2022 à 16:47
 Isfy_18 - 10 déc. 2022 à 16:30

Bonjour,

Je suis en train d'apprendre la programmation python en cours, et pour un programme on a reçu la consigne suivante pour une fonction.

TODO fonction load_anagrams_dict  ...
   Elle reçoit le nom d'un fichier de mots (avec le chemin relatif).
   Elle renvoie un dictionnaire dont la clé est une longueur de mot et 
   la valeur est un dictionnaire dont la clé est une chaîne de caractères 
   triée par ordre croissant et la valeur est un ensemble de mots. 
   Seuls les ensembles contenant au moins deux mots sont conservés.
   Exemple : 
		my_dict = load_anagrams_dict('./resources/dico.txt')
		print(my_dict[6]['EIORTZ'])
		-->
			{'ROTIEZ', 'RIOTEZ'}

La consigne nous demande de créer un dictionnaire à partir d'un fichier texte que l'on a reçu. Le dictionnaire principal a pour clé la longueur du mot, et à chaque clé correspond un dictionnaire ayant pour clé un ensemble de lettres classées dans l'ordre, et pour valeur une liste de mot composés des lettres de la clé.

Après avoir créé ce dictionnaire, il faut que pour une longueur de mot donnée, les clés associées à des listes de moins de deux éléments soient supprimées.

J'ai essayé de faire cette dernière opération avec une boucle for, mais une fois la clé supprimée, un message d'erreur me dit que le dictionnaire à changé de taille, et la boucle ne continue pas.

Voici mon code. Pour le rendre plus simple, j'ai utilisé une série de mots repris dans le fichier texte qui m'a été fourni, et j'ai un peu adapté mon code.

import io

LEN_MIN = 3
LEN_MAX = 10
f = io.StringIO('''
TEL
LET
AAS
ACE
TAS
SAT
CASSER
DETRUIRE
FAIS
FIAS
SAIN
NIAS
PERCE
CREPE
ROTIEZ
RIOTEZ
EBOULEZ
BOUELEZ
DILATENT
DELITANT
SAINTETES
TETANISES
BARBOTERAS
REABSORBAT
  ''')


def load_anagram_dict(f):
	dictionnaire = {}
	word_list = f.readlines()
	for word in word_list:
		word = word.replace("\n", "")
		sorted_word = "".join(sorted(word))
		if LEN_MIN <= len(word) <= LEN_MAX:
			if len(word) not in dictionnaire:
				dictionnaire[len(word)] = {sorted_word: [word]}
			else:
				if sorted_word in dictionnaire[len(word)]:
					dictionnaire[len(word)][sorted_word] += [word]
				else:
					dictionnaire[len(word)].update({sorted_word: [word]})
	print(dictionnaire)

	for i in dictionnaire.keys():
		for j in dictionnaire[i].keys():
			if len(dictionnaire[i][j]) < 2:
				dictionnaire[i].pop(j)

	return dictionnaire


dico = load_anagram_dict(f)
print(dico[3])

J'espère que mon message aura été assez clair.

Merci d'avance.

A voir également:

2 réponses

                dictionnaire[i].pop(j)
Quelle est la nature de dictionnaire[i]? Une liste? Un dictionnaire?
Et si tu faisais un del() ? Ça ne marcherais pas plus.

On ne peut pas modifier un dictionnaire pendant qu'on le parcours.

On peut regénérer le sous-dictionnaire avec une compréhension:

dictionnaire[i] = {k: v for k, v in dictionnaire[i].items() if len(v) >= 2}
1

Merci beaucoup.

0
mamiemando Messages postés 32958 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 27 février 2024 7 724
Modifié le 12 déc. 2022 à 15:36

Bonjour

On ne peut pas modifier un dictionnaire pendant qu'on le parcours.

Pour être plus exact, on ne peut pas supprimer ou créer une clé présente dans un dict (ou dans un set). Mais, lorssqu'on itère sur un dictionnaire, il reste possible de modifier la valeur associée à une clé.

Comment supprimer un ensemble de clés

Il y a deux manières de procéder :

  1. Soit on recrée le dictionnaire filtré "from scratch" (on peut par exemple utiliser une compréhension comme le propose Pierrot le fou #1)
  2. Soit on se débrouille pour que la boucle n'itère pas sur le dictionnaire que l'on modifie, mais par exemple un ensemble préalable construit de clés à supprimer.

La deuxième méthode est plus élégante car dans le pire des cas on construit en mémoire un ensemble dont la taille est celle des clés, alors que pour la première on construit dans le pire ds cas en mémoire deux fois le dictionnaire dans sa totalité.

Exemple

# Create a dummy dict
d = {
    chr(i) : i
    for i in range(97, 107)
}
print(f"d = {d}")

# Define keys to remove
bad_keys = {
    k
    for (k, v) in d.items()
    if v % 2 == 0
}
print(f"bad_keys = {bad_keys}")

# Remove each bad key
for k in bad_keys:
    del d[k]
print(f"d = {d}")

Résultat :

d = {'a': 97, 'b': 98, 'c': 99, 'd': 100, 'e': 101, 'f': 102, 'g': 103, 'h': 104, 'i': 105, 'j': 106}
bad_keys = {'j', 'f', 'b', 'd', 'h'}
d = {'a': 97, 'c': 99, 'e': 101, 'g': 103, 'i': 105}

Version raccourcie :

# Create a dummy dict
d = {
    chr(i) : i
    for i in range(97, 107)
}
print(f"d = {d}")

# Remove some key / value pairs
for k in {
    k
    for (k, v) in d.items()
    if v % 2 == 0
}:
    del d[k]
print(f"d = {d}")

Bonne chance

1

Merci beaucoup, je vais essayer les deux méthodes.

0