Las respuestas existentes solo son correctas si se ignoran los modificadores Unicode / grupos de grafemas. Me ocuparé de eso más tarde, pero primero eche un vistazo a la velocidad de algunos algoritmos de inversión:
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
Puede ver que el tiempo para la comprensión de la lista (reversed = string[::-1]
) es en todos los casos el más bajo (incluso después de corregir mi error tipográfico).
Inversión de cuerdas
Si realmente quieres invertir una cadena en el sentido común, es MUCHO más complicado. Por ejemplo, tome la siguiente cadena ( dedo marrón apuntando hacia la izquierda , dedo amarillo apuntando hacia arriba ). Esos son dos grafemas, pero 3 puntos de código unicode. El adicional es un modificador de piel .
example = "👈🏾👆"
Pero si lo invierte con cualquiera de los métodos dados, obtendrá el dedo marrón apuntando hacia arriba , el dedo amarillo apuntando hacia la izquierda . La razón de esto es que el modificador de color "marrón" todavía está en el medio y se aplica a lo que esté antes. Entonces tenemos
- U: dedo apuntando hacia arriba
- M: modificador marrón
- L: dedo apuntando a la izquierda
y
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
Los clústeres de grafemas Unicode son un poco más complicados que solo los puntos de código modificador. Afortunadamente, hay una biblioteca para manejar grafemas :
>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']
y por lo tanto la respuesta correcta sería
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
que también es, con mucho, el más 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
El 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()