Я сделал много Googling, но ничего не нашел, поэтому мне очень жаль, если я просто искал неправильные вещи.
Я пишу реализацию Ghost для MIT Введение в программирование, назначение 5.
Как часть этого, мне нужно определить, является ли строка символов началом любого действительного слова. У меня есть список допустимых слов ( "список слов" ).
Обновление: я мог бы использовать что-то, что повторялось в списке каждый раз, например, простое предложение Peter:
def word_exists(wordlist, word_fragment):
return any(w.startswith(word_fragment) for w in wordlist)
Я ранее имел:
wordlist = [w for w in wordlist if w.startswith(word_fragment)]
(из здесь), чтобы сузить список до списка допустимых слов, начинающихся с этого фрагмента, и считать потерю, если список слов пуст. Причина, по которой я использовал этот подход, заключалась в том, что я (неправильно, см. Ниже) думал, что это сэкономит время, так как последующие поиски должны были бы искать меньший список.
Мне пришло в голову, что это происходит через каждый элемент в исходном списке слов (38 000 с лишним слов), проверяющих начало каждого из них. Это кажется глупым, когда список слов упорядочен, и понимание может прекратиться, как только оно ударит то, что после фрагмента слова. Я пробовал это:
newlist = []
for w in wordlist:
if w[:len(word_fragment)] > word_fragment:
# Take advantage of the fact that the list is sorted
break
if w.startswith(word_fragment):
newlist.append(w)
return newlist
но это примерно такая же скорость, которая, как я думал, может быть потому, что в списках понимаются как скомпилированный код?
Затем я подумал, что более эффективным будет некоторая форма бинарного поиска в списке, чтобы найти блок совпадающих слов. Это путь, или я пропущу что-то действительно очевидное?
Ясно, что в этом случае это не очень важно, но я только начинаю программировать и хочу делать что-то правильно.
UPDATE:
С тех пор я проверил приведенные ниже предложения с помощью простого теста script. Хотя бинарный поиск Peter/bisect, очевидно, был бы лучше для одного прогона, меня интересовал, победит ли список сужений над несколькими фрагментами. На самом деле это не так:
The totals for all strings "p", "py", "pyt", "pyth", "pytho" are as follows:
In total, Peter simple test took 0.175472736359
In total, Peter bisect left test took 9.36985015869e-05
In total, the list comprehension took 0.0499348640442
In total, Neil G bisect took 0.000373601913452
Накладные расходы на создание второго списка и т.д. явно занимали больше времени, чем поиск более длинного списка. Оглядываясь назад, это, вероятно, лучший подход, независимо от того, как подход "сокращенного списка" увеличил время для первого запуска, что было наихудшим сценарием.
Спасибо всем за отличные предложения, и хорошо сделал Питер за лучший ответ!!!