Le risposte esistenti sono corrette solo se i modificatori Unicode / i cluster grapheme vengono ignorati. Ci penserò più avanti, ma prima diamo un'occhiata alla velocità di alcuni algoritmi di inversione:
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
Potete vedere che il tempo per la comprensione dell'elenco ( reversed = string[::-1]
) è in ogni caso di gran lunga il più basso (anche dopo aver corretto il mio errore di battitura).
Inversione di stringa
Se vuoi davvero invertire una stringa nel senso comune, è MODO più complicato. Ad esempio, prendi la seguente stringa ( dito marrone che punta a sinistra , dito giallo che punta in alto ). Questi sono due grafemi, ma 3 punti di codice unicode. Quello aggiuntivo è un modificatore di skin .
example = "👈🏾👆"
Ma se lo inverti con uno dei metodi indicati, ottieni il dito marrone rivolto verso l'alto , il dito giallo che punta a sinistra . La ragione di ciò è che il modificatore di colore "marrone" è ancora nel mezzo e viene applicato a tutto ciò che lo precede. Quindi abbiamo
- U: dito rivolto verso l'alto
- M: modificatore marrone
- L: dito puntato a sinistra
e
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
I cluster Unicode Grapheme sono un po 'più complicati dei semplici punti di codice modificatore. Fortunatamente, esiste una libreria per la gestione dei grafemi :
>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']
e quindi la risposta corretta sarebbe
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
che è anche di gran lunga il più 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
Il codice
#!/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()