Python的str对象没有内置的反向函数。实施此方法的最佳方式是什么?

如果提供一个非常简洁的答案,请详细说明其效率。例如,str对象是否转换为其他对象等。


使用切片:

>>> 'hello world'[::-1]
'dlrow olleh'

切片符号采用[start:stop:step]的形式。在这种情况下,我们省略了开始和停止位置,因为我们需要整个字符串。我们还使用step=-1,意思是“从右到左重复一个字符”。


@保罗的s[::-1]是最快的;较慢的方法(可能更可读,但这是有争议的)是“”.join(颠倒)。


在python中反转字符串,而不使用reversed()或[::-1]

def reverse(test):
    n = len(test)
    x=""
    for i in range(n-1,-1,-1):
        x += test[i]
    return x

为字符串实现反向函数的最佳方法是什么?

我自己在这个问题上的经验是学术性的。然而,如果你是一个寻找快速答案的专业人士,请使用一个步骤为-1的切片:

>>> 'a string'[::-1]
'gnirts a'

或者更可读(但由于方法名查找以及给定迭代器时join形成列表的事实,速度较慢),str.join:

>>> ''.join(reversed('a string'))
'gnirts a'

或者为了可读性和可重用性,将切片放在函数中

def reversed_string(a_string):
    return a_string[::-1]

然后:

>>> reversed_string('a_string')
'gnirts_a'

更长的解释

如果你对学术博览会感兴趣,请继续阅读。

Python的str对象中没有内置的反向函数。

下面是关于Python字符串的一些事情,您应该知道:

在Python中,字符串是不可变的。更改字符串不会修改字符串。它创建了一个新的。字符串是可滑动的。对字符串进行切片可以以给定的增量从字符串中的一个点向后或向前到另一个点创建一个新字符串。它们采用切片符号或下标中的切片对象:字符串[下标]

下标通过在大括号中包含冒号来创建切片:

    string[start:stop:step]

要在大括号外创建切片,需要创建切片对象:

    slice_obj = slice(start, stop, step)
    string[slice_obj]

可读方法:

虽然“”.join(reversed('o'))是可读的,但它需要在另一个被调用的函数上调用字符串方法str.join,这可能相对较慢。让我们把这个放在一个函数中——我们会回到它:

def reverse_string_readable_answer(string):
    return ''.join(reversed(string))

最高效的方法:

使用反向切片要快得多:

'foo'[::-1]

但是,我们如何让不太熟悉片段或原作者意图的人更容易阅读和理解呢?让我们在下标表示法之外创建一个切片对象,给它一个描述性名称,并将其传递给下标表示法。

start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]

按功能实施

为了将其实际实现为一个函数,我认为仅使用一个描述性名称在语义上就足够清楚了:

def reversed_string(a_string):
    return a_string[::-1]

用法很简单:

reversed_string('foo')

你的老师可能想要什么:

如果你有一个指导老师,他们可能希望你从一个空字符串开始,并从旧字符串中建立一个新字符串。您可以使用while循环使用纯语法和文本来实现这一点:

def reverse_a_string_slowly(a_string):
    new_string = ''
    index = len(a_string)
    while index:
        index -= 1                    # index = index - 1
        new_string += a_string[index] # new_string = new_string + character
    return new_string

这在理论上是不好的,因为记住,字符串是不可变的,所以每次看起来像是在new_string上附加一个字符时,理论上每次都会创建一个新字符串!然而,CPython知道如何在某些情况下优化这一点,这是一个微不足道的例子。

最佳实践

从理论上讲,更好的方法是将子字符串收集到列表中,然后加入它们:

def reverse_a_string_more_slowly(a_string):
    new_strings = []
    index = len(a_string)
    while index:
        index -= 1                       
        new_strings.append(a_string[index])
    return ''.join(new_strings)

然而,正如我们将在下面的CPython计时中看到的,这实际上需要更长的时间,因为CPython可以优化字符串连接。

计时

以下是时间安排:

>>> a_string = 'amanaplanacanalpanama' * 10
>>> min(timeit.repeat(lambda: reverse_string_readable_answer(a_string)))
10.38789987564087
>>> min(timeit.repeat(lambda: reversed_string(a_string)))
0.6622700691223145
>>> min(timeit.repeat(lambda: reverse_a_string_slowly(a_string)))
25.756799936294556
>>> min(timeit.repeat(lambda: reverse_a_string_more_slowly(a_string)))
38.73570013046265

CPython优化了字符串连接,而其他实现可能不会:

…不依赖CPython对a+=b或a=a+b形式的语句的就地字符串连接的高效实现。这种优化即使在CPython中也是脆弱的(它只适用于某些类型),并且在不使用引用计数的实现中根本不存在。在库的性能敏感部分,应改用“”.jjoin()形式。这将确保在各种实现中以线性时间进行连接。


这里有一个不花哨的:

def reverse(text):
    r_text = ''
    index = len(text) - 1

    while index >= 0:
        r_text += text[index] #string canbe concatenated
        index -= 1

    return r_text

print reverse("hello, world!")

def reverse(input):
    return reduce(lambda x,y : y+x, input)

快速回答(TL;DR)

实例

### example01 -------------------
mystring  =   'coup_ate_grouping'
backwards =   mystring[::-1]
print(backwards)

### ... or even ...
mystring  =   'coup_ate_grouping'[::-1]
print(mystring)

### result01 -------------------
'''
gnipuorg_eta_puoc
'''

详细答案

出身背景

提供此答案是为了解决@odigity的以下问题:

哇!起初我对保罗提出的解决方案感到震惊,但坐在后排,我读了第一本书后感到恐惧评论:“这很像蟒蛇。干得好!”一个聪明的社区认为用这种神秘的方法来做这样的事情basic是个好主意。为什么不只是s.reverse()?

问题

上下文Python 2.xPython 3.x脚本:开发人员希望转换字符串转换是颠倒所有字符的顺序

解决方案

example01使用扩展切片表示法生成所需的结果。

陷阱

开发人员可能需要类似string.reverse()的内容本机惯用(又称“pythonic”)解决方案可能对较新的开发人员不可读开发人员可能会尝试实现自己版本的string.reverse(),以避免切片表示法。在某些情况下,切片符号的输出可能与直觉相反:参见例如示例02打印'coup_ate_grouping'[-4:]##=>'ping'与…相比打印'coup_ate_grouping'[-4:-1]##=>'pin'与…相比打印'coup_ate_grouping'[-1]##=>'g'对[-1]进行索引的不同结果可能会让一些开发人员望而却步

根本原因

Python有一个特殊的情况需要注意:字符串是一种可迭代的类型。

排除string.reverse()方法的一个理由是让python开发人员有动力利用这种特殊情况的力量。

简单地说,这意味着字符串中的每个字符都可以作为元素顺序排列的一部分进行操作,就像其他编程语言中的数组一样。

为了了解这是如何工作的,回顾示例02可以提供一个很好的概述。

示例02

### example02 -------------------
## start (with positive integers)
print 'coup_ate_grouping'[0]  ## => 'c'
print 'coup_ate_grouping'[1]  ## => 'o' 
print 'coup_ate_grouping'[2]  ## => 'u' 

## start (with negative integers)
print 'coup_ate_grouping'[-1]  ## => 'g'
print 'coup_ate_grouping'[-2]  ## => 'n' 
print 'coup_ate_grouping'[-3]  ## => 'i' 

## start:end 
print 'coup_ate_grouping'[0:4]    ## => 'coup'    
print 'coup_ate_grouping'[4:8]    ## => '_ate'    
print 'coup_ate_grouping'[8:12]   ## => '_gro'    

## start:end 
print 'coup_ate_grouping'[-4:]    ## => 'ping' (counter-intuitive)
print 'coup_ate_grouping'[-4:-1]  ## => 'pin'
print 'coup_ate_grouping'[-4:-2]  ## => 'pi'
print 'coup_ate_grouping'[-4:-3]  ## => 'p'
print 'coup_ate_grouping'[-4:-4]  ## => ''
print 'coup_ate_grouping'[0:-1]   ## => 'coup_ate_groupin'
print 'coup_ate_grouping'[0:]     ## => 'coup_ate_grouping' (counter-intuitive)

## start:end:step (or start:end:stride)
print 'coup_ate_grouping'[-1::1]  ## => 'g'   
print 'coup_ate_grouping'[-1::-1] ## => 'gnipuorg_eta_puoc'

## combinations
print 'coup_ate_grouping'[-1::-1][-4:] ## => 'puoc'

结论

对于一些不想花太多时间学习python的采纳者和开发人员来说,与理解python中的切片表示法的工作原理相关的认知负荷可能确实太大了。

然而,一旦了解了基本原理,这种方法相对于固定字符串操作方法的威力就会非常大。

对于那些不这么想的人,有其他方法,例如lambda函数、迭代器或简单的一次性函数声明。

如果需要,开发人员可以实现自己的string.reverse()方法,但最好理解python这方面的原理。

另请参见

替代简单方法替代简单方法切片表示法的另一种解释


一个不那么令人困惑的方法是:

string = 'happy'
print(string)

“快乐”

string_reversed = string[-1::-1]
print(string_reversed)

'伊帕'

英语[-1::-1]如下:

“从-1开始,一直走,采取-1的步骤”


递归方法:

def reverse(s): return s[0] if len(s)==1 else s[len(s)-1] + reverse(s[0:len(s)-1])

例子:

print(reverse("Hello!"))    #!olleH

下面是如何使用for循环反转字符串:

string = "hello,world"
for i in range(-1,-len(string)-1,-1):
    print (string[i], end=(" "))

1.使用切片表示法

def rev_string(s): 
    return s[::-1]

2.使用reversed()函数

def rev_string(s): 
    return ''.join(reversed(s))

3.使用递归

def rev_string(s): 
    if len(s) == 1:
        return s

    return s[-1] + rev_string(s[:-1])

这也是一种有趣的方式:

def reverse_words_1(s):
    rev = ''
    for i in range(len(s)):
        j = ~i  # equivalent to j = -(i + 1)
        rev += s[j]
    return rev

或类似:

def reverse_words_2(s):
    rev = ''
    for i in reversed(range(len(s)):
        rev += s[i]
    return rev

另一种更“奇特”的方式使用支持.reverse()的字节数组

b = bytearray('Reverse this!', 'UTF-8')
b.reverse()
b.decode('UTF-8')`

将产生:

'!siht esreveR'

def reverse_string(string):
    length = len(string)
    temp = ''
    for i in range(length):
        temp += string[length - i - 1]
    return temp

print(reverse_string('foo')) #prints "oof"

这通过循环一个字符串并将其值按相反顺序分配给另一个字符串来实现。


original = "string"

rev_index = original[::-1]
rev_func = list(reversed(list(original))) #nsfw

print(original)
print(rev_index)
print(''.join(rev_func))

以编程方式解决面试问题

def reverse_a_string(string: str) -> str:
    """
    This method is used to reverse a string.
    Args:
        string: a string to reverse

    Returns: a reversed string
    """
    if type(string) != str:
        raise TypeError("{0} This not a string, Please provide a string!".format(type(string)))
    string_place_holder = ""
    start = 0
    end = len(string) - 1
    if end >= 1:
        while start <= end:
            string_place_holder = string_place_holder + string[end]
            end -= 1
        return string_place_holder
    else:
        return string


a = "hello world"
rev = reverse_a_string(a)
print(rev)

输出:

dlrow olleh

 a=input()
 print(a[::-1])

上述代码接收来自用户的输入,并通过添加[::-1]打印与输入相反的输出。

输出:

>>> Happy 
>>> yppaH

但当涉及到句子的情况时,请查看下面的代码输出:

>>> Have a happy day
>>> yad yppah a evaH

但如果您只想反转字符串的字符,而不想反转字符串序列,请尝试以下操作:

a=input().split() #Splits the input on the basis of space (" ")
for b in a: #declares that var (b) is any value in the list (a)
    print(b[::-1], end=" ") #End declares to print the character in its quotes (" ") without a new line.

在上面第2行的代码中,我说**变量b是列表(a)中的任何值**我说var a是一个列表,因为当你在输入中使用split时,输入的变量变成了一个列表。还要记住,在int(input())的情况下不能使用split

输出:

>>> Have a happy day
>>> evaH a yppah yad

如果我们不在上面的代码中添加end(“”),那么它将按如下方式打印:

>>> Have a happy day
>>> evaH
>>> a
>>> yppah
>>> yad

下面是一个了解end()的示例:

代码:

for i in range(1,6):
     print(i) #Without end()

输出:

>>> 1
>>> 2
>>> 3
>>> 4
>>> 5

现在使用end()编写代码:

for i in range(1,6):
    print(i, end=" || ")

输出:

>>> 1 || 2 || 3 || 4 || 5 ||

有多种方法可以在Python中反转字符串

切片方法

string = "python"
rev_string = string[::-1]
print(rev_string)

使用反向函数

string = "python"
rev= reversed(string) 
rev_string = "".join(rev) 
print(rev_string)

使用递归

string = "python"
def reverse(string):
  if len(string)==0:
    return string
  else:
    return reverse(string[1:])+string[0]
print(reverse(string))

使用for循环

string = "python"
rev_string =""
for s in string:
  rev_string = s+ rev_string
print(rev_string)

使用while循环

string = "python"
rev_str =""
length = len(string)-1
while length >=0:
  rev_str += string[length]
  length -= 1
print(rev_str)

作为一种不同的解决方案(因为面试中会问到):

def reverse_checker(string):
    ns = ""
    for h in range(1,len(string)+1):
        ns  += string[-h]
    print(ns)

    if ns == string:
        return True
    else:
        return False