Разбор списка слов в питоне - PullRequest
1 голос
/ 07 марта 2011

У меня есть файл wlist.txt, содержащий около 58 тыс. Слов английского языка, небольшая выдержка которого выглядит следующим образом:перечислите и посмотрите, содержится ли слово в списке, и если да, выведите слово.Моя проблема в том, что код, который я написал, будет постоянно возвращать, что нет, слова нет в списке, когда я точно знаю, что это так.Мой код выглядит так, кто-нибудь замечает какие-либо ошибки?

match = 'aardvark'
f = 'wlist.txt'
success = False
try:
    for word in open(f):
        if word == match:
            success = True
            break
except IOError:
    print f, "not found!"
if success:
    print "The word has been found with a value of", word
else:
    print "Word not found"

Заранее всем спасибо !!

Ответы [ 11 ]

6 голосов
/ 07 марта 2011

Как уже говорили другие, ваша проблема связана с тем, что символы новой строки являются частью слов, которые вы читаете. Лучший способ избавиться от них - это использовать strip() метод str.

Кроме того, ваш код делает слишком много для выполнения простой задачи.Все, что вам нужно сделать, это создать set из вашего списка слов и искать вхождение вашего слова в набор.set гораздо лучше для этой задачи, чем list, потому что проверка на наличие элемента в set намного быстрее .Так что-то вроде этого должно работать.

try:
    with open('wordlist.txt', 'rU') as infile:
        wordSet = set(line.strip() for line in infile)
except IOError:
       print 'error opening file'

aWord = 'aardvark'

if aWord in wordSet:
    print 'found word', aWord
else:
    print 'word not found'

Примечание: if aWord in wordSet - это , поэтому намного быстрее, это не смешно.Если вы ищете слово ближе к концу списка слов, set почти в 60000 раз быстрее для списка из 267000 слов.И это все еще немного быстрее даже , если вы ищете самое первое слово.

3 голосов
/ 07 марта 2011

Вот код, который должен работать

match = 'aardvark'
    f = 'wlist.txt'
    success = False
    try:
        for word in open(f):
            if word.strip() == match: # Change here 
                success = True
                break
    except IOError:
        print f, "not found!"
    if success:
        print "The word has been found with a value of", word
    else:
        print "Word not found"
3 голосов
/ 07 марта 2011

Всем дан хороший совет о том, как это сделать, но вам действительно нужно использовать python?

grep aardvark wlist.txt

Это почти наверняка разрушит любое решение на основе Python для скорости. fgrep, вероятно, будет еще быстрее.

1 голос
/ 07 марта 2011

Ваша проблема гораздо проще решить. Вы не поняли, что можете прочитать весь список в памяти по очень скромной цене - ваш файл меньше 1 МБ, он отлично помещается в памяти.

Решением вашей проблемы является чтение всего объекта в массив и использование стандартных методов списка для поиска членства:

# this is the only thing you need to get all the words in memory
words = [w.strip() for w in open("words.txt", "rb").readlines()]

# this is the only thing you need to find wether a word is in the list
print 'aaron' in words
# returns 'True'

# now you can go around many times and ask for membership of any word, 
# or any list of words (use a loop) - the array is already in memory 
# and will stay there until you close the program - it's only 1 mega!

Можно утверждать, что мое решение не является умным, но я думаю, что оно практично - преждевременная оптимизация - корень всего зла , и, пытаясь написать умный цикл, вы упускаете совершенно простой подход, который с учетом вашей проблемы работает отлично (кстати, первый вызов функции занимает меньше секунды для текстового файла из 60 тысяч слов, каждый поиск также чрезвычайно быстр) .

Обратите внимание: вам не нужен set (вам все равно, если слово повторяется - ответ тот же).

Не решайте не ту проблему!

PS. Многие люди думают, что 58 тыс. Слов - это «много» - это (58 + средняя длина) кБ (если слова ~ 10 букв каждое, это 580 кБ - около половины мегабайта). Когда я слышу, как люди говорят, что вы не должны открывать это в памяти, я удивляюсь, как они открывают свои фотографии! Это парадигма, которую нужно сломать. Люди будут требовать «, но ваша программа не является надежной, потому что, если список станет 100 миллионами строк, он сломает », и это справедливо в мире, где английский язык увеличит свой словарный запас на 10 порядков величина. Мы часто забываем, что general означает general для вашего домена .

Редактировать : Согласно комментариям @Chinmay, использование набора над списком имеет серьезные последствия для доступа. Используя список из 58 тысяч слов, я выполнил два 1000 упражнения на доступ: list и set (время доступа в микросекундах):

container    min    max   mean
list           3   1646  724.4
set            1     31    1.6

Итак, как указывает @Chinmay, среднее время доступа для набора почти на три порядка меньше. Это может иметь значение, если вы обращаетесь к словам много раз (что вы, вероятно, и есть).

Итак, я исправил и изменил код так:

# create a set of words
words = set(w.strip() for w in open('file.txt').readlines())

# test access using the `in` operator, as :
'aaron' in words
# will return True

Моя точка зрения остается: решение этой проблемы намного проще, чем создание class для реализации оператора членства.

1 голос
/ 07 марта 2011

Вот мое очень простое предложение:

wordlist = map(str.strip, open("wlist.txt", "r").readlines())
if word in wordlist:
   print "The word has been found with a value of", word
else:
   print "Word not found"
1 голос
/ 07 марта 2011
file = open(f)
words = set( (line.strip() for line in file.readlines()) )
file.close()

if match in words:
    print "The word has been found with a value of", word
else:
    print "Word not found"
1 голос
/ 07 марта 2011

Попробуйте заменить word == match на word[0:-1] == match, чтобы удалить символ новой строки в конце word.

Редактировать: Альтернативно, заменить word == match на word.rstrip() == match какпредложил в этот вопрос.

1 голос
/ 07 марта 2011

Итерация на файловых объектах включает переводы строк.

0 голосов
/ 13 марта 2019

Думаю, вы можете сделать это с помощью регулярных выражений (пере) в Python. Просто импортируйте библиотеку повторно используя import re re.search (шаблон, источник) или re.findall (шаблон, источник)

с открытым ('wordlist.txt', 'rU') как infile: для элемента в infile.readlines ():

if re.search(r'^aardvark',item):
    print('word found')
else:
    print('word not found')
0 голосов
/ 07 марта 2011

Проблема в опубликованном вами коде состоит в том, что перебор открытого файла включает символы newline .Другие ответы касаются этой проблемы.

Этот ответ указывает на то, что стратегия очень неэффективна, если поиск следует проводить часто.

Если поиск будет выполняться несколько раз, то лучше всего сохранить список слов как Trie , что позволяет O(m) поисков, с m, являющимсяДлина искомой строки при построении Три имеет сложность, аналогичную поиску в списке слов по одному слову.Trie может быть сохранен на диск (замаринован?) Для быстрого поиска.

Поиск слова по словарю с помощью опубликованного кода занимает время, пропорциональное размеру словаря, равному O(n).Сборка Trie - это O(n+C), с большим C, что оправдывает его, только если будут частые поиски.

Я посмотрел, и в Интернете говорится, что существует несколько реализацийTrie в Python готов попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...