Как сделать рефакторинг функции сжатия строки для устранения повторяющегося кода?
Что проверяют
Умеете ли вы увидеть настоящую причину дублирования, а не спрятать повтор во вспомогательную функцию. Второе, что смотрят: пишете ли вы тесты до правки, ведь рефакторинг по определению не меняет поведение. Следом обычно спрашивают про сложность и крайние случаи.
Как отвечать
В типичной реализации сжатия ("aaab" в "a3b1") код добавления группы повторяется дважды: в цикле при смене символа и после цикла для последней группы. Вынести эту строку в append_compressed() мало, вызов всё равно остаётся в двух местах. Дублирование исчезает, когда меняется сама структура:
from itertools import groupby
def compress(s: str) -> str:
return "".join(f"{ch}{sum(1 for _ in grp)}" for ch, grp in groupby(s))groupby сам отдаёт последнюю группу, особый случай пропадает, пустая строка обрабатывается без отдельного if.
Без itertools хвост убирают так:
- единая точка сброса: цикл по индексам до
len(s)включительно, группа закрывается, когда индекс вышел за строку или символ сменился; - список частей и
join: собирать вparts.append(...), в конце"".join(parts). Конкатенация+=в цикле в худшем случае квадратичная, а оптимизация CPython на месте не гарантирована; - тесты до правки:
pytest.mark.parametrizeна пустую строку, один символ, строку без повторов, строку из одного символа, серии длиннее 9.
Хорошо задать вопросы к постановке. Писать a1 или просто a для одиночного символа? Возвращать ли исходную строку, если сжатая не короче? Что делать с цифрами во входе, ведь "a11" уже нельзя однозначно распаковать?
Где спотыкаются
Выносят конкатенацию в функцию, которая принимает строку и возвращает строку, и называют это рефакторингом. Повтор остался, а читать стало труднее.
Незаметно меняют поведение: убирают 1 у одиночных символов или ломают пустую строку. Без тестов, зафиксированных до правки, это проходит незамеченным.
Путают groupby с группировкой по всей строке, как в SQL. Он склеивает только соседние одинаковые элементы: для "aba" будет три группы. Для RLE это ровно то, что нужно, а для подсчёта частот символов берут Counter.