Подсчет вхождений слова в текст
Условие
Напишите функцию, которая подсчитывает количество вхождений каждого слова в тексте.
Пример
Вход: hello world hello Выход: {hello: 2, world: 1}
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Развернутый ответ на задачу о подсчете вхождений слов
В качестве QA Automation инженера с 10+ лет опыта, я подхожу к этой задаче не только с точки зрения написания рабочего кода, но и с учетом тестируемости, производительности, читаемости и потенциальных крайних случаев. Задача кажется простой, но в реальных проектах она часто усложняется требованиями к обработке разных языков, пунктуации, регистра и производительности на больших объемах данных.
Ключевые аспекты реализации
- Нормализация текста: Приведение к нижнему регистру для регистронезависимого подсчета.
- Токенизация: Разделение текста на слова. Важно корректно обработать пунктуацию и пробелы.
- Структура данных: Использование словаря (хэш-таблицы) для подсчета, так как операции добавления и поиска в среднем занимают O(1).
- Обработка крайних случаев: Пустая строка, повторяющиеся пробелы, знаки препинания, смешанные языки.
Базовая реализация на Python
def count_words(text):
"""
Подсчитывает количество вхождений каждого слова в тексте.
Args:
text (str): Входной текст для анализа.
Returns:
dict: Словарь, где ключи - слова, значения - количество их вхождений.
Возвращает пустой словарь для пустого или состоящего только из пробелов текста.
Пример:
>>> count_words("hello world hello")
{'hello': 2, 'world': 1}
>>> count_words("Hello, world! Hello!")
{'hello': 2, 'world': 1}
"""
if not text or text.isspace():
return {}
# 1. Нормализация: приводим к нижнему регистру
normalized_text = text.lower()
# 2. Токенизация: удаляем знаки препинания и разбиваем по пробелам
# Более надежный способ - использовать регулярные выражения
import re
# \w+ соответствует последовательностям буквенно-цифровых символов и подчеркивания
# Добавим поддержку апострофов в словах типа "it's" -> ["it", "s"]? Нет, оставим "it's".
# Для большинства задач подходит шаблон, включающий буквы (включая Unicode) и апострофы.
words = re.findall(r"[a-zа-яё0-9']+", normalized_text)
# 3. Подсчет с использованием словаря
word_count = {}
for word in words:
# Можно использовать .get() или collections.defaultdict
word_count[word] = word_count.get(word, 0) + 1
return word_count
# Пример использования
if __name__ == "__main__":
test_text = "Hello, world! Hello again. The world is great, isn't it?"
result = count_words(test_text)
print(result) # {'hello': 2, 'world': 2, 'again': 1, 'the': 1, 'is': 1, 'great': 1, "isn't": 1, 'it': 1}
Альтернативная, более эффективная реализация с использованием collections.Counter
from collections import Counter
import re
def count_words_counter(text):
"""Более питоничная и эффективная версия с использованием Counter."""
if not text or text.isspace():
return {}
words = re.findall(r"[a-zа-яё0-9']+", text.lower())
return dict(Counter(words))
Тестовое покрытие как QA Automation инженер
Для полноценного решения я бы обязательно написал юнит-тесты, покрывающие основные и крайние случаи:
import pytest
def test_count_words_basic():
assert count_words("hello world hello") == {"hello": 2, "world": 1}
def test_count_words_case_insensitive():
assert count_words("Hello World hElLo") == {"hello": 2, "world": 1}
def test_count_words_with_punctuation():
assert count_words("Hello, world! Hello...") == {"hello": 2, "world": 1}
def test_count_words_empty_string():
assert count_words("") == {}
def test_count_words_only_spaces():
assert count_words(" \n\t ") == {}
def test_count_words_single_word():
assert count_words("test") == {"test": 1}
def test_count_words_with_apostrophe():
# Важно: решение с шаблоном [a-zа-яё0-9']+ сохранит апостроф внутри слова
result = count_words("It's a test. Don't panic!")
assert result.get("it's") == 1
assert result.get("don't") == 1
assert result.get("a") == 1
def test_count_words_unicode():
# Поддержка кириллицы (если шаблон включает а-яё)
assert count_words("привет мир привет") == {"привет": 2, "мир": 1}
Обсуждение сложности и оптимизаций
- Временная сложность: O(n), где n - длина текста.
re.findallпроходит по строке один раз, последующий подсчет - O(k), где k - количество уникальных слов. - Пространственная сложность: O(k) для хранения словаря с результатами.
- Оптимизации для больших текстов:
* Для обработки файлов гигабайтного размера стоит использовать **поточную обработку** (чтение блоками).
* Можно рассмотреть использование более эффективных структур данных, таких как **Trie (префиксное дерево)**, если нужен поиск по префиксам или автодополнение.
* Для многопоточной обработки очень больших текстов можно разбить текст на части и использовать **многопоточность** или **MapReduce** паттерн.
Вывод для собеседования
Как QA Automation специалист, я бы акцентировал внимание на том, что даже простая задача требует:
- Анализа требований (нужна ли поддержка Unicode, как обрабатывать составные слова, гифены).
- Выбора корректных инструментов (регулярные выражения vs простой split, словарь vs Counter).
- Написания тестов для валидации всех сценариев, включая крайние случаи.
- Документирования функции, особенно поведения с граничными значениями.
- Размышления о масштабировании решения для обработки больших данных.
Эта задача отлично демонстрирует разницу между кодом, который "просто работает", и промышленным решением, готовым к интеграции в реальный проект с высокими требованиями к надежности и поддерживаемости.