Python与回文
我最近写了一个方法,用来遍历 /usr/share/dict/words
这个文件,并通过我的 ispalindrome(x)
方法返回一个回文的列表。这里有一部分代码……它有什么问题呢?它会卡住10分钟,然后才返回文件里的所有单词。
def reverse(a): return a[::-1] def ispalindrome(a): b = reverse(a) if b.lower() == a.lower(): return True else: return False wl = open('/usr/share/dict/words', 'r') wordlist = wl.readlines() wl.close() for x in wordlist: if not ispalindrome(x): wordlist.remove(x) print wordlist
5 个回答
3
我觉得这里有两个问题。
首先,把所有的单词都读进一个列表有什么意义呢?为什么不一个一个处理单词,遇到回文就打印出来呢?
其次,要注意空格的问题。你的每个word
后面都有换行符!
因为你没有正确识别回文(是因为空格的原因),所以你会试图在遍历列表的时候把每个项目都删除掉!
这个解决方案运行得非常快,能识别出很多回文:
for word in open('/usr/share/dict/words', 'r'):
word = word.strip()
if ispalindrome(word):
print word
编辑:
也许更“符合Python风格”的做法是使用生成器表达式:
def ispalindrome(a):
return a[::-1].lower() == a.lower()
words = (word.strip() for word in open('/usr/share/dict/words', 'r'))
palindromes = (word for word in words if ispalindrome(word))
print '\n'.join(palindromes)
3
其他人已经指出了一些更好的解决方案。我想告诉你,为什么在运行你的代码后列表并没有变空。因为你的 ispalindrome()
函数由于之前提到的“换行符问题”永远不会返回 True
,所以你的代码会对每一个项目都调用 wordlist.remove(x)
。那么,为什么最后列表还是不空呢?
因为你在遍历列表的时候同时修改了它。想象一下下面的情况:
>>> l = [1,2,3,4,5,6]
>>> for i in l:
... l.remove(i)
...
>>> l
[2, 4, 6]
当你移除 1
时,剩下的元素会向上移动一步,这样现在 l[0]
就变成了 2
。但是,遍历的计数器已经向前走了,它会在下一次迭代时查看 l[1]
,因此会移除 3
,依此类推。
所以你的代码实际上只移除了列表的一半。总结一下:在遍历列表的时候,绝对不要修改它(除非你非常清楚自己在做什么 :))。
8
wordlist = wl.readlines()
当你这样做的时候,最后会有一个换行符,所以你的列表看起来像这样:
['eye\n','bye\n', 'cyc\n']
这些元素显然不是回文。
你需要这样做:
['eye','bye', 'cyc']
所以要把换行符去掉,这样就没问题了。
可以用一行代码来做到这一点:
wordlist = [line.strip() for line in open('/usr/share/dict/words')]
编辑:遍历一个列表并修改它会导致问题。可以使用列表推导式,正如Matthew所指出的。