# Если бы в body была строка "тест", то после преобразований получилось бы "ест"
"".join((char for num, char in enumerate(self.body) if char != self.body[num - 1]))
Первый символ сравнивался с последним и если они совпадали, то он пропускался — возможно это повлияло на изменение размера индекса.
Если у кого-то есть идеи, как можно оптимизировать функцию на Python по скорости, то отпишитесь в комментариях, я добавлю данные в тесты.
По моим замерам, на 10µs быстрее на одну итерацию
import re
from functools import reduce
# Правила замены гласных
VOWELS = {"(?:йо|ио|йе|ие)": "и", "[оыя]": "а", "[еёэ]": "и", "[ю]": "у"}
# Правила оглушения согласных
CONSONANTS = {"б": "п", "з": "с", "д": "т", "в": "ф"}
# Согласная должна быть оглушена, если за ней следует один из символов списка
DEAFENING_CHARS = "бвгджзй"
# Удаляемые символы
REMOVABLE_CHARS = {ord("ъ"): None, ord("ь"): None}
def _canonicalize(s):
return s.lower().strip()
def _remove_double_chars(s):
return "".join(c for n, c in enumerate(s) if n == 0 or c != s[n - 1])
def _deafen_consonants(s):
out = []
for n, char in enumerate(s):
if char in CONSONANTS and (
n < len(s) - 1 and s[n + 1] in DEAFENING_CHARS
or n == len(s) - 1
):
out.append(CONSONANTS[char])
else:
out.append(char)
return "".join(out)
def _replace_vowels(s):
for pattern, replacement in VOWELS.items():
s = re.sub(pattern, replacement, s)
return s
def _remove_chars(s):
return s.translate(REMOVABLE_CHARS)
return reduce(lambda x, modifier: modifier(x), (
_canonicalize,
_remove_chars,
_replace_vowels,
_deafen_consonants,
_remove_double_chars,
), in_lexeme)
Первый символ сравнивался с последним и если они совпадали, то он пропускался — возможно это повлияло на изменение размера индекса.