Answers:
怎么样:
>>> 'hello world'[::-1]
'dlrow olleh'
这是扩展片语法。它的工作方式是[begin:end:step]
-离开begin和end并指定步骤-1,它反转字符串。
b = a.decode('utf8')[::-1].encode('utf8')
但感谢您的正确指导!
.decode('utf8')
需要,则表示a
不包含任何字符串对象,而是字节。
@Paolo s[::-1]
是最快的;较慢的方法(可能更具可读性,但这值得商))是''.join(reversed(s))
。
join
都必须建立列表才能获取大小。''.join(list(reversed(s)))
可能会更快。
为字符串实现反向函数的最佳方法是什么?
我对这个问题的经验是学术上的。但是,如果您是专业人士在寻找快速答案,请使用按-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[subscript]
下标通过在括号内包含冒号来创建切片:
string[start:stop:step]
要在大括号之外创建切片,您需要创建一个slice对象:
slice_obj = slice(start, stop, step)
string[slice_obj]
虽然''.join(reversed('foo'))
可读,但需要str.join
在另一个调用的函数上调用字符串方法,这可能会比较慢。让我们将其放在函数中-我们将回到它:
def reverse_string_readable_answer(string):
return ''.join(reversed(string))
使用反向切片快得多:
'foo'[::-1]
但是,对于不熟悉切片或原始作者意图的人,我们如何使它更具可读性和可理解性?让我们在下标符号之外创建一个slice对象,为其指定一个描述性名称,然后将其传递给下标符号。
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中,这种优化也是脆弱的(仅适用于某些类型),并且在不使用引用计数的实现中根本没有这种优化。在库的性能敏感部分中,应使用''.join()形式。这将确保在各种实现方式中串联发生在线性时间内。
while
和减少索引,尽管这可能不太容易理解: for i in range(len(a_string)-1, -1, -1):
。我最喜欢的是,您选择的示例字符串是一种您永远不需要将其反转,并且无法告诉您是否具有:)的情况:
### example01 -------------------
mystring = 'coup_ate_grouping'
backwards = mystring[::-1]
print backwards
### ... or even ...
mystring = 'coup_ate_grouping'[::-1]
print mystring
### result01 -------------------
'''
gnipuorg_eta_puoc
'''
提供此答案是为了解决@odigity的以下问题:
哇。起初,我对Paolo提出的解决方案感到震惊,但这使我在读了第一条评论时感到的恐惧退缩了:“那太好了。做得好!” 我感到非常不安,以至于这样一个聪明的社区认为将如此神秘的方法用于如此基本的东西是一个好主意。为什么不只是s.reverse()?
string.reverse()
string.reverse()
以避免切片符号。print 'coup_ate_grouping'[-4:] ## => 'ping'
print 'coup_ate_grouping'[-4:-1] ## => 'pin'
print 'coup_ate_grouping'[-1] ## => 'g'
[-1]
可能会使一些开发人员失望Python有一种特殊的情况要注意:字符串是可迭代的类型。
排除string.reverse()
方法的一个基本原理是给予python开发人员动力以利用这种特殊情况的力量。
简而言之,这简单地意味着字符串中的每个单独字符都可以像其他编程语言中的数组一样容易地作为元素顺序排列的一部分进行操作。
要了解其工作原理,请查看example02可以提供很好的概述。
### 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中的工作方式相关的认知负担确实可能过大。
但是,一旦理解了基本原理,此方法相对于固定字符串操作方法的功能可能会非常有利。
对于那些有其他想法的人,还有其他方法,例如lambda函数,迭代器或简单的一次性函数声明。
如果需要,开发人员可以实现自己的string.reverse()方法,但是最好理解python这方面的原理。
仅当忽略Unicode修饰符/字形群集时,现有答案才是正确的。我将在稍后处理,但首先请看一些反转算法的速度:
list_comprehension : min: 0.6μs, mean: 0.6μs, max: 2.2μs
reverse_func : min: 1.9μs, mean: 2.0μs, max: 7.9μs
reverse_reduce : min: 5.7μs, mean: 5.9μs, max: 10.2μs
reverse_loop : min: 3.0μs, mean: 3.1μs, max: 6.8μs
list_comprehension : min: 4.2μs, mean: 4.5μs, max: 31.7μs
reverse_func : min: 75.4μs, mean: 76.6μs, max: 109.5μs
reverse_reduce : min: 749.2μs, mean: 882.4μs, max: 2310.4μs
reverse_loop : min: 469.7μs, mean: 577.2μs, max: 1227.6μs
您可以看到,列表推导(reversed = string[::-1]
)的时间在所有情况下都是最低的(即使在修正我的错字之后)。
如果您真的想按常识反转字符串,则方法会更加复杂。例如,采用以下字符串(棕色手指指向左,黄色手指指向上)。那是两个字素,但有3个unicode码点。另一个是皮肤修饰剂。
example = "👈🏾👆"
但是,如果使用任何给定的方法将其反转,则会使棕色手指指向上方,黄色手指指向左侧。这样做的原因是“棕色”颜色修改器仍在中间,并应用于之前的任何内容。所以我们有
和
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
Unicode音素簇比修饰符代码点要复杂一些。幸运的是,用于处理库字形:
>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']
因此正确的答案是
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
到目前为止也是最慢的:
list_comprehension : min: 0.5μs, mean: 0.5μs, max: 2.1μs
reverse_func : min: 68.9μs, mean: 70.3μs, max: 111.4μs
reverse_reduce : min: 742.7μs, mean: 810.1μs, max: 1821.9μs
reverse_loop : min: 513.7μs, mean: 552.6μs, max: 1125.8μs
reverse_graphemes : min: 3882.4μs, mean: 4130.9μs, max: 6416.2μs
#!/usr/bin/env python
import numpy as np
import random
import timeit
from functools import reduce
random.seed(0)
def main():
longstring = ''.join(random.choices("ABCDEFGHIJKLM", k=2000))
functions = [(list_comprehension, 'list_comprehension', longstring),
(reverse_func, 'reverse_func', longstring),
(reverse_reduce, 'reverse_reduce', longstring),
(reverse_loop, 'reverse_loop', longstring)
]
duration_list = {}
for func, name, params in functions:
durations = timeit.repeat(lambda: func(params), repeat=100, number=3)
duration_list[name] = list(np.array(durations) * 1000)
print('{func:<20}: '
'min: {min:5.1f}μs, mean: {mean:5.1f}μs, max: {max:6.1f}μs'
.format(func=name,
min=min(durations) * 10**6,
mean=np.mean(durations) * 10**6,
max=max(durations) * 10**6,
))
create_boxplot('Reversing a string of length {}'.format(len(longstring)),
duration_list)
def list_comprehension(string):
return string[::-1]
def reverse_func(string):
return ''.join(reversed(string))
def reverse_reduce(string):
return reduce(lambda x, y: y + x, string)
def reverse_loop(string):
reversed_str = ""
for i in string:
reversed_str = i + reversed_str
return reversed_str
def create_boxplot(title, duration_list, showfliers=False):
import seaborn as sns
import matplotlib.pyplot as plt
import operator
plt.figure(num=None, figsize=(8, 4), dpi=300,
facecolor='w', edgecolor='k')
sns.set(style="whitegrid")
sorted_keys, sorted_vals = zip(*sorted(duration_list.items(),
key=operator.itemgetter(1)))
flierprops = dict(markerfacecolor='0.75', markersize=1,
linestyle='none')
ax = sns.boxplot(data=sorted_vals, width=.3, orient='h',
flierprops=flierprops,
showfliers=showfliers)
ax.set(xlabel="Time in ms", ylabel="")
plt.yticks(plt.yticks()[0], sorted_keys)
ax.set_title(title)
plt.tight_layout()
plt.savefig("output-string.png")
if __name__ == '__main__':
main()
def rev_string(s):
return s[::-1]
def rev_string(s):
return ''.join(reversed(s))
def rev_string(s):
if len(s) == 1:
return s
return s[-1] + rev_string(s[:-1])
RecursionError: maximum recursion depth exceeded while calling a Python object
。例如:rev_string("abcdef"*1000)
观察它的一种比较简单的方法是:
string = 'happy'
print(string)
'快乐'
string_reversed = string[-1::-1]
print(string_reversed)
'yppah'
用英语[-1 ::-1]读为:
“从-1开始,一直走,采取-1的步骤”
-1
仍然不需要的,虽然。
不使用reversed()或[::-1]反转python中的字符串
def reverse(test):
n = len(test)
x=""
for i in range(n-1,-1,-1):
x += test[i]
return x
这也是一种有趣的方式:
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()的BYTERArray的另一种“异国情调”方式
b = bytearray('Reverse this!', 'UTF-8')
b.reverse()
b.decode('UTF-8')
将产生:
'!siht esreveR'
def reverse(input):
return reduce(lambda x,y : y+x, input)
这是一个没有[::-1]
或reversed
(出于学习目的)的:
def reverse(text):
new_string = []
n = len(text)
while (n > 0):
new_string.append(text[n-1])
n -= 1
return ''.join(new_string)
print reverse("abcd")
您可以+=
用来连接字符串,但join()
速度更快。
以上所有解决方案都是完美的,但是如果我们尝试在python中使用for循环来反转字符串会变得有些棘手,所以这是我们如何使用for循环来反转字符串
string ="hello,world"
for i in range(-1,-len(string)-1,-1):
print (string[i],end=(" "))
我希望这对某人有帮助。
反向字符串有很多方法,但我也创建了另一种方法只是为了好玩。我认为这种方法还不错。
def reverse(_str):
list_char = list(_str) # Create a hypothetical list. because string is immutable
for i in range(len(list_char)/2): # just t(n/2) to reverse a big string
list_char[i], list_char[-i - 1] = list_char[-i - 1], list_char[i]
return ''.join(list_char)
print(reverse("Ehsan"))
此类使用python魔术函数反转字符串:
class Reverse(object):
""" Builds a reverse method using magic methods """
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
REV_INSTANCE = Reverse('hello world')
iter(REV_INSTANCE)
rev_str = ''
for char in REV_INSTANCE:
rev_str += char
print(rev_str)
dlrow olleh
使用python 3,您可以就地反转字符串,这意味着它不会被分配给另一个变量。首先,您必须将字符串转换为列表,然后利用该reverse()
函数。
https://docs.python.org/3/tutorial/datastructures.html
def main():
my_string = ["h","e","l","l","o"]
print(reverseString(my_string))
def reverseString(s):
print(s)
s.reverse()
return s
if __name__ == "__main__":
main()
这是简单而有意义的反向功能,易于理解和编码
def reverse_sentence(text):
words = text.split(" ")
reverse =""
for word in reversed(words):
reverse += word+ " "
return reverse
反转没有python魔术的字符串。
>>> def reversest(st):
a=len(st)-1
for i in st:
print(st[a],end="")
a=a-1
当然,在Python中,您可以做非常漂亮的1行内容。:)
这是一个简单,全面的解决方案,可以在任何编程语言中使用。
def reverse_string(phrase):
reversed = ""
length = len(phrase)
for i in range(length):
reversed += phrase[length-1-i]
return reversed
phrase = raw_input("Provide a string: ")
print reverse_string(phrase)
您可以将反向功能与列表综合一起使用。但是我不明白为什么在python 3中取消了这种方法是不必要的。
string = [ char for char in reversed(string)]
.join
或一个使其正确答案的内容
[c for c in string]
等于list(string)
。