1
votes

Pourquoi "if letter in dict" fonctionne mal en Python?

J'essaie d'écrire une fonction, qui renvoie une chaîne de lettres qui ne sont pas en lettres Devine

'abcdfghjlmnoqtuvwxyz' 

alors j'appelle ma fonction

'abcdfghjlmnoqstuvwxyz' 

# the letter 's' in the output, but it shouldn't be there.

Mais le résultat est différent de ce que j'attendais. Ma sortie:

getAvailableLetters(['e', 's', 'i', 'k', 'p', 'r'])

Sortie correcte:

words = list('abcdefghijklmnopqrstuvwxyz')

def getAvailableLetters(lettersGuessed):
    [words.remove(letter) for letter in words if letter in lettersGuessed]
    return ''.join([str(elem) for elem in words]) 

qu'est-ce que je fais de mal?


2 commentaires

Ne supprimez pas d'éléments lors de l'itération dessus. Cela conduira à des comportements inattendus. Vous pouvez parcourir la copie et supprimer les éléments. c'est-à-dire pour lettre en mots [:]: words.remove (lettre) . Il n'est pas non plus nécessaire de construire la liste [words.remove (lettre) pour lettre en mots [:] si lettre en lettresGuessed] . remove est une opération en place et ne donne pas de valeur. Vous êtes donc en train de créer une liste de valeurs None .


Vous modifiez une liste en même temps que vous l'itérez, ce qui signifie que vous sauterez certaines valeurs de la liste. Essayez quelque chose comme return '' .join (l pour l en mots si l pas en lettresGuessed) à la place


3 Réponses :


1
votes

La raison est que vous modifiez une liste tout en l'itérant - cela ne devrait pas être fait. Je vais partager ici le conseil que @AlexMartelli a donné dans l'une de ses réponses :

Ne modifiez jamais le conteneur sur lequel vous bouclez, car les itérateurs de ce conteneur ne seront pas informés de vos modifications et, comme vous l'avez remarqué, cela risque de produire une boucle très différente et / ou incorrecte .

Voici une solution alternative (utilisant également snake_case), utilisant des ensembles - étant donné que ni les lettres disponibles ni les lettres devinées ne contiendraient des doublons (sauf par erreur):

all_letters = list('abcdefghijklmnopqrstuvwxyz')

def get_available_letters(letters_guessed):
    available_letters = [letter for letter in all_letters if letter not in letters_guessed]
    return ''.join([str(letter) for letter in available_letters])


0 commentaires

1
votes

Je vais vous donner un petit exemple pour voir ce qu'il se passe lorsque vous supprimez des éléments d'une liste pendant que vous parcourez:

def getAvailableLetters(lettersGuessed):
    return ''.join(c for c in words if c not in lettersGuessed)

résultat:

'abcdfghjlmnoqtuvwxyz'


0 commentaires

1
votes

La fonction

remove () décrémente la longueur des mots , alors qu'en Python, la variable de boucle est initialisée pour ses limites au début de la boucle uniquement. Essayez de comprendre cela avec un petit exemple

lis = [1, 2, 4, 6, 5]
for i in lis:
    if i % 2 == 0:
        lis.remove(i)

Ce code affiche [1, 4, 5] , alors que le résultat attendu est [1, 5] . En effet, i a déjà été initialisé pour passer de 0 à 5 index. La première fois que lis.remove () a supprimé 2, la longueur de lis a diminué et il a été mis à jour en lis = [1, 4, 6, 5] , et maintenant je devrais pointer vers 4 (l'élément suivant), alors que je pointe maintenant vers 6, c'est-à-dire l'index 2 (parce que 2 était à l'index 1), et donc ne vérifie jamais la valeur 4. La même chose se passe dans votre code. p>

Pour la solution, il est préférable d'utiliser la boucle while . Ce problème ne se pose pas avec la boucle while, mais uniquement avec les boucles for.


0 commentaires