Что лучше использовать для подсчёта повторений слов в большом файле: генератор или итератор в Python
Что проверяют
Знаете ли вы терминологию: генератор это частный случай итератора, и противопоставление в вопросе ложное. Заодно смотрят, понимаете ли, что память здесь ограничена словарём счётчиков, а не размером файла.
Как отвечать
Начать с того, что выбор мнимый. Любая функция с yield возвращает итератор, а файловый объект сам по себе итератор и отдаёт строки по одной, не загружая файл целиком.
from collections import Counter
def count_words(path):
with open(path, encoding="utf-8") as f:
return Counter(w for line in f for w in line.lower().split())Проход ленивый, а Counter обновляется циклом на стороне C, что заметно быстрее ручного инкремента в словаре. Дальше оговорки, которые и отличают ответ от заученного:
- расход памяти определяется числом уникальных слов. На естественном языке это сотни тысяч ключей и проблемы нет, на логах с идентификаторами внутри строк словарь может не влезть;
- если не влезает, слова шардируют по
hash(w) % Nв N временных файлов, считают порознь и складывают счётчики; - разбиение по пробелам это не токенизация: нужны регулярное выражение и приведение регистра, иначе слово с запятой станет отдельным ключом.
Где спотыкаются
Пишут f.read().split() или readlines(). Файл целиком уезжает в память, и на десятках гигабайт процесс убивает нехватка памяти, хотя сам алгоритм подсчёта корректен.
Второе: ждут от генератора ускорения. Он экономит память, а не время, и цепочка генераторных выражений из-за вызова на каждый элемент бывает даже медленнее обычного цикла.
Третье: забывают, что итератор одноразовый. Второй проход по тому же генератору даёт пустоту, а не повтор, поэтому посчитать сначала общее число слов, а потом уникальные по одному объекту не выйдет.