Les réponses existantes ne sont correctes que si les modificateurs Unicode / grappes de graphèmes sont ignorés. J'y reviendrai plus tard, mais jetons d'abord un coup d'œil à la vitesse de certains algorithmes d'inversion:
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
Vous pouvez voir que le temps pour la liste comprehension ( reversed = string[::-1]
) est dans tous les cas de loin le plus bas (même après avoir corrigé ma faute de frappe).
Inversion de chaîne
Si vous voulez vraiment inverser une chaîne dans le bon sens, c'est BEAUCOUP plus compliqué. Par exemple, prenez la chaîne suivante ( doigt brun pointant vers la gauche , doigt jaune pointant vers le haut ). Ce sont deux graphèmes, mais 3 points de code unicode. Le second est un modificateur de skin .
example = "👈🏾👆"
Mais si vous l'inversez avec l'une des méthodes indiquées, vous obtenez un doigt brun pointant vers le haut , un doigt jaune pointant vers la gauche . La raison en est que le modificateur de couleur "marron" est toujours au milieu et appliqué à tout ce qui le précède. Donc nous avons
- U: doigt pointé vers le haut
- M: modificateur marron
- L: doigt pointé vers la gauche
et
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
Les grappes de graphèmes Unicode sont un peu plus compliquées que les simples points de code de modificateur. Heureusement, il existe une bibliothèque pour gérer les graphèmes :
>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']
et donc la bonne réponse serait
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
qui est aussi de loin le plus lent:
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
Le code
#!/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()