Функция, которая переворачивает строку каждый раз, когда в ней появляется гласная?

Я пытаюсь создать функцию, которая для каждого появления гласной в строке переворачивает указанную строку (и включает гласную, когда она это делает). Насколько я понимаю, эта функция несколько сложна, поэтому мне нужна помощь и, возможно, ее разбивка. Однако Я хотел бы использовать только операторы и операторы, которые я сейчас изучаю (для/пока и если). Если возможно, я также хотел бы избежать использования понимания списка.

Вот как должны выглядеть входы и выходы:

пример ввода будет reverse_per_vowel('aerith') который возвращает 'iraeth'

Если разбить процесс этой функции на шаги, то должно получиться так:

(а)эфир → (а)эфир (первая буква гласная, поэтому она перевернута. Однако, поскольку это первая буква в строке, видимых изменений нет.)

(aе)рит → (еa)рит (вторая буква также является гласной, поэтому каждая буква в строке, предшествующая гласной и включающая ее, переворачивается.)

(earя)th → (яrae)th (четвертая буква - гласная, поэтому все, что до нее и включая ее, также перевернуто. Обратите внимание, как он учитывает буквы в строке, которые ранее были перевернуты.)

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

Что я пытаюсь

vowellist = 'aeiouAEIOU'
sampleword = 'aerith'

indexlist = []
for i in range(len(sampleword)):
    if sampleword[i] in vowel_list:
        indexlist.append(i)
indexlist

вывод: [0, 1, 3]

этот отрывок не переворачивает какие-либо части строки, однако возвращает индексы, в которых строка должна быть перевернута. Что я планировал сделать, так это каким-то образом подключить эти индексы обратно к образцу слова и использовать [::-1] для реверсирования части строки. Однако я не знаю, как бы я это сделал, и было бы это хорошей идеей. Любая помощь будет оценена по достоинству.

Анализ настроения постов в Twitter с помощью Python, Tweepy и Flair
Анализ настроения постов в Twitter с помощью Python, Tweepy и Flair
Анализ настроения текстовых сообщений может быть настолько сложным или простым, насколько вы его сделаете. Как и в любом ML-проекте, вы можете выбрать...
7 лайфхаков для начинающих Python-программистов
7 лайфхаков для начинающих Python-программистов
В этой статье мы расскажем о хитростях и советах по Python, которые должны быть известны разработчику Python.
Установка Apache Cassandra на Mac OS
Установка Apache Cassandra на Mac OS
Это краткое руководство по установке Apache Cassandra.
Сертификатная программа "Кванты Python": Бэктестер ансамблевых методов на основе ООП
Сертификатная программа "Кванты Python": Бэктестер ансамблевых методов на основе ООП
В одном из недавних постов я рассказал о том, как я использую навыки количественных исследований, которые я совершенствую в рамках программы TPQ...
Создание персонального файлового хранилища
Создание персонального файлового хранилища
Вы когда-нибудь хотели поделиться с кем-то файлом, но он содержал конфиденциальную информацию? Многие думают, что электронная почта безопасна, но это...
Создание приборной панели для анализа данных на GCP - часть I
Создание приборной панели для анализа данных на GCP - часть I
Недавно я столкнулся с интересной бизнес-задачей - визуализацией сбоев в цепочке поставок лекарств, которую могут просматривать врачи и...
4
0
56
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Один из простых способов добиться этого — использовать рекурсию:

vowels = set('aeiouAEIOU')

def reverse_per_vowel(s):
    if not s: # empty string
        return ''
    beforelast, last = s[:-1], s[-1]
    if last in vowels:
        return last + reverse_per_vowel(beforelast)[::-1]
    return reverse_per_vowel(beforelast) + last

print(reverse_per_vowel('aerith')) # iraeth

Вы можете сделать это с помощью простой модификации вашей петли for и некоторых расширенных нарезок:

vowellist = 'aeiouAEIOU'
sampleword = 'aerith'

for i in range(len(sampleword)):
    if sampleword[i] in vowellist:
        sampleword = sampleword[i::-1] + sampleword[i + 1:]

print(sampleword)

Каждую итерацию, если появляется гласная, вы можете просто переназначить строку с новой частично перевернутой. Выход:

iraeth

Вы можете помочь моей стране, отметьте информация моего профиля.

Ответ принят как подходящий

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

И да, вы можете использовать этот алгоритм:

  • Постройте две струны. Они начинаются пустыми, а второй из них помечается как «активный».

  • Посетите ввод символов в обратном порядке: от последнего к первому

    • Пока они согласные, добавьте их в текущую активную строку.
    • Когда это гласная, переключите активную строку на другую и добавьте туда гласную.
  • В конце этого процесса инвертируйте вторую строку и верните конкатенацию двух строк:

VOWELS = set("aeiouAEIOU")

def reverse_per_vowel(s):
    endings = ["", ""]
    side = 1
    for c in reversed(s):
        if c in VOWELS:
            side = 1 - side  # Toggle between 0 and 1
        endings[side] += c
    return endings[0] + endings[1][::-1]

Поскольку этот алгоритм не реверсирует каждый раз, когда встречается с гласной, а выполняет только одно реверсирование в конце, он работает с линейной временной сложностью, в отличие от того, что вы получили бы, если бы вы реализовали описанный процесс буквально, что имеет временную сложность в наихудшем случае. O (n²).

При таком анализе сложности я предполагаю, что расширение строки с помощью символа — это процесс с постоянным временем. Если есть сомнения по этому поводу, то реализуйте его с двумя списками символов, вызывая append и выполняя join в конце процесса, чтобы получить окончательную строку:

VOWELS = set("aeiouAEIOU")

def reverse_per_vowel(s):
    endings = [[], []]
    side = 1
    for c in reversed(s):
        if c in VOWELS:
            side = 1 - side  # Toggle between 0 and 1
        endings[side].append(c)
    
    return "".join(endings[0] + endings[1][::-1])

Использование списка делает его очень простым и понятным:

def reverse_per_vowel(word):
    result = []
    for letter in word:
        result.append(letter)
        if letter in 'aeiouAEIOU':
            result.reverse()
    return ''.join(result)

Это также быстро. Для вашего образца слова это было быстрее, чем все другие решения, опубликованные до сих пор, а для слова из 1000 букв ('aerith' * 167) только второе решение @trincot было немного быстрее, остальные были в 2–10 раз медленнее. В конце концов, конечно, он действительно проигрывает второму решению Тринкота, которое при 10 000 букв было примерно в 5 раз быстрее, а при 100 000 букв примерно в 46 раз быстрее.

А вот еще один с линейным временем, немного быстрее, чем у тринкота (проверено на строках, содержащих до миллиона букв). Он помещает буквы в очередь, чтобы можно было эффективно добавлять слева или справа. И у него есть флаг, который сообщает, является ли результат в настоящее время обратным.

from collections import deque

def reverse_per_vowel(word):
    result = deque()
    reverse = False
    for letter in word:
        if not reverse:
            result.append(letter)
        else:
            result.appendleft(letter)
        if letter in 'aeiouAEIOU':
            reverse = not reverse
    if reverse:
        result.reverse()
    return ''.join(result)

Другие вопросы по теме