As respostas existentes estão corretas apenas se os clusters Unicode Modifiers / grafema forem ignorados. Lidarei com isso mais tarde, mas primeiro observe a velocidade de alguns algoritmos de reversão:
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
Você pode ver que o tempo para a compreensão da lista ( reversed = string[::-1]
) é em todos os casos de longe o mais baixo (mesmo depois de corrigir meu erro de digitação).
Reversão de String
Se você realmente deseja reverter uma string no senso comum, é MUITO mais complicado. Por exemplo, pegue a seguinte corda ( dedo marrom apontando para a esquerda , dedo amarelo apontando para cima ). Esses são dois grafemas, mas três pontos de código unicode. O adicional é um modificador de capa .
example = "👈🏾👆"
Mas se você o reverter com qualquer um dos métodos fornecidos, o dedo marrom será apontado para cima , o dedo amarelo apontado para a esquerda . A razão para isso é que o modificador de cor "marrom" ainda está no meio e é aplicado ao que estiver antes dele. Então nós temos
- U: dedo apontando para cima
- M: modificador marrom
- L: dedo apontando para a esquerda
e
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
Os Clusters Unicode Grapheme são um pouco mais complicados do que apenas pontos de código modificadores. Felizmente, existe uma biblioteca para lidar com grafemas :
>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']
e, portanto, a resposta correta seria
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
que também é de longe o mais lento:
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
O código
#!/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()