Вопрос

Недавно я написал метод для прохождения /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
Это было полезно?

Решение

wordlist = wl.readlines()

Когда вы делаете это, в конце появился новый линейный персонаж, так что ваш список похож на:

['eye\n','bye\n', 'cyc\n']

Элементы которых, очевидно, не палиндром.

Ты нуждаешься в этом:

['eye','bye', 'cyc']

Так strip Новый персонаж, и это должно быть хорошо.

Сделать это в одной строке:

wordlist = [line.strip() for line in open('/usr/share/dict/words')]

РЕДАКТИРОВАТЬ: Итерация над списком и изменение его вызывает проблемы. Используйте понимание списка, как указано Мэтью.

Другие советы

Другие уже указали на лучшие решения. Я хочу показать вам, почему список не пуст после запуска вашего кода. С тех пор, как ты 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 и так далее.

Таким образом, ваш код удаляет половину записей. Мораль: Никогда не изменяйте список, пока вы итерации по нему (если только вы не знаете, что делаете :)).

Я думаю, что есть две проблемы.

Во -первых, какой смысл читать все слова в список? Почему бы не обработать каждое слово по очереди и распечатать его, если это палиндром.

Во -вторых, следите за пробелом. У вас есть новички в конце каждого из ваших wordS!

Поскольку вы не идентифицируете каких -либо палиндромов (из -за пробела), вы попытаетесь удалить каждый элемент из списка. Пока вы итерации над этим!

Это решение проходит за секунду и идентифицирует много палиндромов:

for word in open('/usr/share/dict/words', 'r'):
    word = word.strip()
    if ispalindrome(word):
        print word

Редактировать:

Возможно, более «питоническое» - это использовать генератор выражения:

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)

Это не возвращает все слова. Он возвращается наполовину. Это потому, что вы изменяете список во время итерации над ним, что является ошибкой. Более простым и более эффективным решением является использование понимания списка. Вы можете изменить сухбир, чтобы сделать все это:

[word for word in (word.strip() for word in wl.readlines()) if ispalindrome(word)]

Вы также можете разорвать это:

stripped = (word.strip() for word in wl.readlines())
wordlist = [word for word in stripped if ispalindrome(word)]

Вы включаете Newline в конце каждого слова в /usr/share/dict/words. Анкет Это означает, что вы никогда не найдете палиндромов. Вы ускоряете ситуацию, если вы просто зарегистрируете палиндромы, когда найдете их, вместо того, чтобы удалять не палиндромы из списка.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top