Python与回文

2 投票
5 回答
3395 浏览
提问于 2025-04-16 09:49

我最近写了一个方法,用来遍历 /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所指出的。

撰写回答