简体   繁体   English

每次出现元音时反转字符串的函数?

[英]function that reverses a string every time a vowel appears in it?

I'm trying to make a function that, for every occurrence of a vowel in a string, reverses said-string (and includes the vowel when it does this).我正在尝试创建一个函数,对于字符串中每次出现的元音,反转 said-string(并在执行此操作时包括元音)。 The function is somewhat complex for my understanding so I'd like some help and a maybe a breakdown of it.就我的理解而言,该功能有些复杂,因此我需要一些帮助并可能对其进行细分。 However, I would only like to use the operators and statements that I'm currently learning (for/while and if).但是,我只想使用我目前正在学习的运算符和语句(for/while 和 if)。 If possible, I would also like to avoid using list comprehension.如果可能的话,我也想避免使用列表理解。

Here's what the inputs and outputs should look like:输入和输出应该是这样的:

an example input would be reverse_per_vowel('aerith') which returns 'iraeth'一个示例输入是reverse_per_vowel('aerith')返回'iraeth'

If we break the process of this function into steps, it should look like:如果我们把这个函数的过程分解成几个步骤,它应该是这样的:

( a )erith → ( a )erith ( the first letter is a vowel, so it is reversed. However, because it is the first letter in the string, there are no visible changes. ) ( a )erith → ( a )erith (第一个字母是元音,所以颠倒了。但是,因为它是字符串中的第一个字母,所以没有可见的变化。

(a e )rith → ( e a)rith ( the second letter is also a vowel, so every letter in the string leading up to and including the vowel is reversed. ) (a e )rith → ( e a)rith (第二个字母也是元音,所以字符串中直到元音并包括元音的每个字母都被颠倒了。

(ear i )th → ( i rae)th ( the fourth letter is a vowel, so everything leading up to and including it is also reversed. Note how it accounts for the letters in the string that were reversed previously. ) (ear i )th → ( i rae)th (第四个字母是元音,所以它之前和包括它的所有内容也被颠倒了。注意它是如何解释字符串中先前被颠倒的字母的。

as you can see, the amount of times the string is reversed is cumulative and I'm not quite sure how to code for this.如您所见,字符串反转的次数是累积的,我不太确定如何为此编码。 However, I've attempted to write a component of the function.但是,我试图编写该函数的一个组件。

What I'm trying我在尝试什么

vowellist = 'aeiouAEIOU'
sampleword = 'aerith'

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

output: [0, 1, 3]输出: [0, 1, 3]

this excerpt does not reverse any parts of the string, however it returns indexes where the string should be reversed.此摘录不会反转字符串的任何部分,但会返回应反转字符串的索引。 What I planned on doing was plugging these indexes back into the sample word somehow and using [::-1] to reverse a portion of the string.我计划做的是以某种方式将这些索引插入到示例单词中,并使用 [::-1] 来反转字符串的一部分。 However, I don't know how I would do this nor if it would be a good idea.但是,我不知道该怎么做,也不知道这是否是个好主意。 Any help would be appreciated.任何帮助,将不胜感激。

If there are many vowels, then the repeated reversals seem like they could be avoided, as a second reversal somewhat is an undo of the previous reversal.如果有很多元音,那么重复的反转似乎是可以避免的,因为第二次反转在某种程度上是对前一次反转的撤销。

And yes, you could use this algorithm:是的,你可以使用这个算法:

  • Build two strings.构建两个字符串。 They start emtpy, and mark the second of them as the "active" one.他们开始是空的,并将其中第二个标记为“活动”。

  • Visit the input characters in reversed order: from last to first以相反的顺序访问输入的字符:从最后到第一个

    • As long as they are consonants add them to the currently active string只要它们是辅音就将它们添加到当前活动的字符串中
    • When it is a vowel, switch the active string to be the other one, and add the vowel there当它是元音时,将活动字符串切换为另一个,并在那里添加元音
  • At the end of this process, reverse the second string and return the concatenation of the two strings:在此过程结束时,反转第二个字符串并返回两个字符串的串联:

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]

As this algorithm is not reversing each time it meets a vowel, but only performs one reversal at the end, it runs with linear time complexity, contrary to what you would get if you implement the described process literally, which has a worst case time complexity of O(n²).由于该算法不会在每次遇到元音时都反转,而是在最后只执行一次反转,因此它以线性时间复杂度运行,这与您按字面意思执行所描述的过程会得到的结果相反,后者具有最坏情况的时间复杂度O(n²)。

With this complexity analysis I assume that extending a string with a character is a constant time process.通过这种复杂性分析,我假设用字符扩展字符串是一个常数时间过程。 If there is doubt about this, then implement it with two lists of characters, calling append and perform a join at the end of the process to get the final string:如果对此有疑问,则用两个字符列表实现它,调用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])

One easy way to achieve this is to use recursion:实现此目的的一种简单方法是使用递归:

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

You can do it with simple modification of your for loop and some advanced slicing:您可以通过简单修改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)

Every iteration if vowel appears you can just reassign string with new partly reversed.如果出现元音,则每次迭代都可以重新分配新的部分反转的字符串。 Output:输出:

iraeth

Using a list makes it very easy and clean:使用列表使它变得非常简单和干净:

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

It's also fast.它也很快。 For your sample word, it was faster than all the other solutions posted so far, and for a word with 1000 letters ( 'aerith' * 167 ), only @trincot's second solution was a bit faster, the others were 2 to 10 times slower.对于你的示例单词,它比目前发布的所有其他解决方案都快,对于一个有 1000 个字母的单词 ( 'aerith' * 167 ),只有@trincot 的第二个解决方案快一点,其他的慢 2 到 10 倍. Eventually of course it really loses to trincot's second solution, which at 10,000 letters was about 5 times faster and at 100,000 letters was about 46 times faster.当然,最终它真的输给了 trincot 的第二个解决方案,后者在 10,000 个字母时快了大约 5 倍,在 100,000 个字母时快了大约 46 倍。

And here's another linear-time one, a bit faster than trincot's (tested on strings with up to a million letters).这是另一个线性时间的,比 trincot 的快一点(在包含多达一百万个字母的字符串上测试)。 It puts the letters into a deque so it can efficiently append to the left or to the right.它将字母放入一个双端队列中,因此它可以有效地附加到左侧或右侧。 And it has a flag that tells whether the result is currently in reverse.它有一个标志,告诉当前结果是否是反向的。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM