为什么Python中的“if-letter in-dict”工作错误?
我正在尝试编写一个函数,它返回一个字符串,该字符串中的字母不是LettersGuesed为什么Python中的“if-letter in-dict”工作错误?,python,string,list,if-statement,list-comprehension,Python,String,List,If Statement,List Comprehension,我正在尝试编写一个函数,它返回一个字符串,该字符串中的字母不是LettersGuesed words = list('abcdefghijklmnopqrstuvwxyz') def getAvailableLetters(lettersGuessed): [words.remove(letter) for letter in words if letter in lettersGuessed] return ''.join([str(elem) for elem in wor
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])
然后我调用我的函数
getAvailableLetters(['e', 's', 'i', 'k', 'p', 'r'])
但结果与我预期的不同。
我的输出:
'abcdfghjlmnoqstuvwxyz'
# the letter 's' in the output, but it shouldn't be there.
正确输出:
'abcdfghjlmnoqtuvwxyz'
我做错了什么?原因是您在遍历列表时正在修改列表-不应该这样做。 我将在这里分享@AlexMartelli给出的建议: 永远不要更改正在循环的容器,因为容器上的迭代器不会被通知您的更改,而且正如您所注意到的,这很可能会产生一个非常不同的循环和/或一个不正确的循环 这里有一个替代解决方案,也使用snake_case,使用集合——假设可用字母和猜测字母都不包含重复字母,除非是错误:
all_letters = set('abcdefghijklmnopqrstuvwxyz')
def get_available_letters(letters_guessed):
available_letters = all_letters - set(letters_guessed)
return ''.join([str(letter) for letter in available_letters])
这里有一个警告,上面的解决方案可能不遵守您指定字母的顺序
如果您仍想坚持列表,请分两个阶段进行:
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])
原因是您在遍历列表时正在修改它-不应该这样做。 我将在这里分享@AlexMartelli给出的建议: 永远不要更改正在循环的容器,因为容器上的迭代器不会被通知您的更改,而且正如您所注意到的,这很可能会产生一个非常不同的循环和/或一个不正确的循环 这里有一个替代解决方案,也使用snake_case,使用集合——假设可用字母和猜测字母都不包含重复字母,除非是错误:
all_letters = set('abcdefghijklmnopqrstuvwxyz')
def get_available_letters(letters_guessed):
available_letters = all_letters - set(letters_guessed)
return ''.join([str(letter) for letter in available_letters])
这里有一个警告,上面的解决方案可能不遵守您指定字母的顺序
如果您仍想坚持列表,请分两个阶段进行:
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])
我将给您一个小示例,以了解在迭代时从列表中删除元素时发生的情况:
l = ['a', 'b', 'c', 'd', 'e', 'f']
for i, c in enumerate(l):
print('_' * 25)
print('iteration', i)
print('index value', i)
print('elemnt at index ', i, ':', l[i])
print('list length:', len(l))
l.remove(c)
print('\nafter removing an element')
print('list length:', len(l))
print('index value', i)
if len(l) > i:
print('elemnt at index ', i, ':', l[i]) # this element will not be removed
print('_' * 40)
print('list after iterateion:', l)\
输出:
_________________________
iteration 0
index value 0
elemnt at index 0 : a
list length: 6
after removing an element
list length: 5
index value 0
elemnt at index 0 : b
_________________________
iteration 1
index value 1
elemnt at index 1 : c
list length: 5
after removing an element
list length: 4
index value 1
elemnt at index 1 : d
_________________________
iteration 2
index value 2
elemnt at index 2 : e
list length: 4
after removing an element
list length: 3
index value 2
elemnt at index 2 : f
________________________________________
list after iterateion: ['b', 'd', 'f']
如您所见,如果在迭代列表时删除一个元素,则会修改列表的大小,并且从一个迭代到另一个迭代,则会跳过下一个元素,for循环在每次迭代后都会随着索引的增加而增加,希望抓住下一个元素,但您会使用一个元素来收缩列表,因此for循环实际上会跳过1个元素
如果要修改全局变量字,可以使用:
def getAvailableLetters(lettersGuessed):
global words
words = [c for c in words if c not in lettersGuessed]
return ''.join([str(elem) for elem in words])
getAvailableLetters(['e', 's', 'i', 'k', 'p', 'r'])
输出:
_________________________
iteration 0
index value 0
elemnt at index 0 : a
list length: 6
after removing an element
list length: 5
index value 0
elemnt at index 0 : b
_________________________
iteration 1
index value 1
elemnt at index 1 : c
list length: 5
after removing an element
list length: 4
index value 1
elemnt at index 1 : d
_________________________
iteration 2
index value 2
elemnt at index 2 : e
list length: 4
after removing an element
list length: 3
index value 2
elemnt at index 2 : f
________________________________________
list after iterateion: ['b', 'd', 'f']
如果只想返回不在LettersGuesed中的字母,而不修改全局变量字:
我将给您一个小示例,以了解在迭代时从列表中删除元素时发生的情况:
l = ['a', 'b', 'c', 'd', 'e', 'f']
for i, c in enumerate(l):
print('_' * 25)
print('iteration', i)
print('index value', i)
print('elemnt at index ', i, ':', l[i])
print('list length:', len(l))
l.remove(c)
print('\nafter removing an element')
print('list length:', len(l))
print('index value', i)
if len(l) > i:
print('elemnt at index ', i, ':', l[i]) # this element will not be removed
print('_' * 40)
print('list after iterateion:', l)\
输出:
_________________________
iteration 0
index value 0
elemnt at index 0 : a
list length: 6
after removing an element
list length: 5
index value 0
elemnt at index 0 : b
_________________________
iteration 1
index value 1
elemnt at index 1 : c
list length: 5
after removing an element
list length: 4
index value 1
elemnt at index 1 : d
_________________________
iteration 2
index value 2
elemnt at index 2 : e
list length: 4
after removing an element
list length: 3
index value 2
elemnt at index 2 : f
________________________________________
list after iterateion: ['b', 'd', 'f']
如您所见,如果在迭代列表时删除一个元素,则会修改列表的大小,并且从一个迭代到另一个迭代,则会跳过下一个元素,for循环在每次迭代后都会随着索引的增加而增加,希望抓住下一个元素,但您会使用一个元素来收缩列表,因此for循环实际上会跳过1个元素
如果要修改全局变量字,可以使用:
def getAvailableLetters(lettersGuessed):
global words
words = [c for c in words if c not in lettersGuessed]
return ''.join([str(elem) for elem in words])
getAvailableLetters(['e', 's', 'i', 'k', 'p', 'r'])
输出:
_________________________
iteration 0
index value 0
elemnt at index 0 : a
list length: 6
after removing an element
list length: 5
index value 0
elemnt at index 0 : b
_________________________
iteration 1
index value 1
elemnt at index 1 : c
list length: 5
after removing an element
list length: 4
index value 1
elemnt at index 1 : d
_________________________
iteration 2
index value 2
elemnt at index 2 : e
list length: 4
after removing an element
list length: 3
index value 2
elemnt at index 2 : f
________________________________________
list after iterateion: ['b', 'd', 'f']
如果只想返回不在LettersGuesed中的字母,而不修改全局变量字:
remove函数减少单词的长度,而在Python中,循环变量仅在循环开始时针对其限制进行初始化。试着用一个小例子来理解这一点
lis = [1, 2, 4, 6, 5]
for i in lis:
if i % 2 == 0:
lis.remove(i)
此代码输出[1,4,5],而预期输出为[1,5]。这是因为,我已经初始化为从0到5索引。第一次lis.remove删除2时,lis的长度减少了,它被更新为lis=[1,4,6,5],现在我应该指向下一个元素的4,而现在我指向6,即索引2,因为2位于索引1,因此从不检查值4。同样的情况也发生在代码中
对于解决方案,最好使用while循环。这个问题不会出现在while循环中,而只出现在for循环中。remove函数会减少单词的长度,而在Python中,循环变量仅在循环开始时初始化其限制。试着用一个小例子来理解这一点
lis = [1, 2, 4, 6, 5]
for i in lis:
if i % 2 == 0:
lis.remove(i)
此代码输出[1,4,5],而预期输出为[1,5]。这是因为,我已经初始化为从0到5索引。第一次lis.remove删除2时,lis的长度减少了,它被更新为lis=[1,4,6,5],现在我应该指向下一个元素的4,而现在我指向6,即索引2,因为2位于索引1,因此从不检查值4。同样的情况也发生在代码中
对于解决方案,最好使用while循环。while循环不会出现此问题,但仅for循环会出现此问题。迭代时不要删除元素。这将导致意外的行为。您可以迭代副本并删除元素。例如,单词中的字母[:]:words.removeletter。还有
re无需构建列表[单词中的字母的单词。移除字母[:]如果字母中的字母已被选中]。移除是一个就地操作,不会产生值。因此,实际上您正在构建一个无值列表。您在迭代列表的同时修改列表,这意味着您将跳过列表中的一些值。尝试类似于return.joinl的方法,如果l不在LettersGuesed中,则在单词中表示l,在迭代时不要删除元素。这将导致意外的行为。您可以迭代副本并删除元素。例如,单词中的字母[:]:words.removeletter。此外,也不需要构建列表[words.removeletter for letter in words[:]如果letter in letters被选中]。移除是一个就地操作,不会产生值。因此,实际上您正在构建一个无值列表。您在迭代列表的同时修改列表,这意味着您将跳过列表中的一些值。尝试一些类似return的方法。如果我不是用字母表示,那么用单词表示l