Odpowiedzi:
Co powiesz na:
>>> 'hello world'[::-1]
'dlrow olleh'
Jest to rozszerzona składnia plasterka . Działa poprzez zrobienie [begin:end:step]- pozostawiając początek i koniec i określając krok -1, odwraca ciąg.
b = a.decode('utf8')[::-1].encode('utf8')ale dziękuję za właściwy kierunek!
.decode('utf8')jest to wymagane, oznacza to, że anie zawiera żadnych ciągów znaków, a raczej bajtów.
@ Paolo's s[::-1]jest najszybszy; wolniejsze podejście (może bardziej czytelne, ale to dyskusyjne) ''.join(reversed(s)).
join musi zbudować listę, aby uzyskać rozmiar. ''.join(list(reversed(s)))może być nieco szybszy.
Jaki jest najlepszy sposób implementacji funkcji odwrotnej dla ciągów?
Moje własne doświadczenia z tym pytaniem są akademickie. Jeśli jednak jesteś profesjonalistą szukającym szybkiej odpowiedzi, użyj fragmentu, który krok po kroku -1:
>>> 'a string'[::-1]
'gnirts a'
lub bardziej czytelnie (ale wolniej z powodu wyszukiwania nazw metod i faktu, że join tworzy listę, gdy otrzyma się iterator) str.join:
>>> ''.join(reversed('a string'))
'gnirts a'
lub dla czytelności i ponownego użycia, wstaw plasterek do funkcji
def reversed_string(a_string):
return a_string[::-1]
i wtedy:
>>> reversed_string('a_string')
'gnirts_a'
Jeśli jesteś zainteresowany wykładem akademickim, czytaj dalej.
W obiekcie str Pythona nie ma wbudowanej funkcji odwrotnej.
Oto kilka rzeczy na temat ciągów Python, które powinieneś wiedzieć:
W Pythonie ciągi są niezmienne . Zmiana łańcucha nie powoduje modyfikacji łańcucha. Tworzy nowy.
Struny można kroić. Przecięcie łańcucha daje nowy ciąg z jednego punktu łańcucha, do tyłu lub do przodu, do innego punktu, o podane przyrosty. Pobierają notację plasterka lub obiekt plasterka w indeksie dolnym:
string[subscript]Indeks dolny tworzy wycinek, włączając dwukropek w nawiasy klamrowe:
string[start:stop:step]
Aby utworzyć plasterek poza nawiasami klamrowymi, musisz utworzyć obiekt plasterka:
slice_obj = slice(start, stop, step)
string[slice_obj]
Chociaż ''.join(reversed('foo'))jest czytelny, wymaga wywołania metody łańcuchowej str.join, na innej wywoływanej funkcji, która może być względnie wolna. Umieśćmy to w funkcji - wrócimy do tego:
def reverse_string_readable_answer(string):
return ''.join(reversed(string))
Znacznie szybsze jest stosowanie odwrotnego wycinka:
'foo'[::-1]
Ale w jaki sposób możemy uczynić to bardziej czytelnym i zrozumiałym dla osoby mniej obeznanej z wycinkami lub intencjami oryginalnego autora? Utwórzmy obiekt wycinka poza notacją indeksu dolnego, nadajmy mu opisową nazwę i przekażmy go notacji indeksu dolnego.
start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]
Aby faktycznie zaimplementować to jako funkcję, myślę, że jest to semantycznie wystarczająco jasne, aby po prostu użyć opisowej nazwy:
def reversed_string(a_string):
return a_string[::-1]
A użycie jest po prostu:
reversed_string('foo')
Jeśli masz instruktora, prawdopodobnie chcą, abyś zaczął od pustego łańcucha i zbudował nowy łańcuch ze starego. Możesz to zrobić przy użyciu czystej składni i literałów za pomocą pętli 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
Jest to teoretycznie złe, ponieważ pamiętaj, że ciągi są niezmienne - więc za każdym razem, gdy wygląda na to, że dodajesz do siebie znak new_string, teoretycznie za każdym razem tworzy się nowy ciąg! Jednak CPython wie, jak to zoptymalizować w niektórych przypadkach, z których ten trywialny przypadek jest jednym.
Teoretycznie lepiej jest zebrać swoje podciągi na liście i dołączyć do nich później:
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)
Jednak, jak zobaczymy poniżej, dla CPython, tak naprawdę trwa to dłużej, ponieważ CPython może zoptymalizować konkatenację łańcucha.
Oto czasy:
>>> 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 optymalizuje konkatenację łańcuchów, podczas gdy inne implementacje mogą nie :
... nie polegaj na efektywnej implementacji CPython w miejscu łączenia konkatenacji ciągów dla instrukcji w postaci a + = b lub a = a + b. Ta optymalizacja jest krucha nawet w CPython (działa tylko dla niektórych typów) i nie jest wcale obecna w implementacjach, które nie używają przeliczania. W wrażliwych na wydajność częściach biblioteki należy zamiast tego użyć formularza .join (). Zapewni to, że konkatenacja nastąpi w czasie liniowym w różnych implementacjach.
whilei zmniejszanie wskaźnika, choć być może jest to mniej czytelny: for i in range(len(a_string)-1, -1, -1): . Przede wszystkim kocham, że przykład ciąg wybrałeś jest jeden przypadek, w którym nigdy nie trzeba go odwrócić, i nie będzie w stanie powiedzieć, czy miałeś :)
### example01 -------------------
mystring = 'coup_ate_grouping'
backwards = mystring[::-1]
print backwards
### ... or even ...
mystring = 'coup_ate_grouping'[::-1]
print mystring
### result01 -------------------
'''
gnipuorg_eta_puoc
'''
Ta odpowiedź ma na celu zaradzenie następującym obawom @odigity:
Łał. Na początku przeraziło mnie rozwiązanie zaproponowane przez Paolo, ale zajęło to miejsce z przerażeniem, które odczułem po przeczytaniu pierwszego komentarza: „To bardzo pytoniczne. Dobra robota!” Jestem tak zaniepokojony, że tak błyskotliwa społeczność myśli o użyciu tak tajemniczych metod dla czegoś tak podstawowego, to dobry pomysł. Dlaczego nie jest to po prostu s.reverse ()?
string.reverse()string.reverse()aby uniknąć notacji plastra.print 'coup_ate_grouping'[-4:] ## => 'ping'print 'coup_ate_grouping'[-4:-1] ## => 'pin'print 'coup_ate_grouping'[-1] ## => 'g'[-1]mogą zniechęcić niektórych programistówPython ma szczególną okoliczność, o której należy pamiętać: ciąg znaków jest typem iterowalnym .
Jednym z powodów wykluczenia string.reverse()metody jest zachęcenie programistów python do wykorzystania siły tej szczególnej okoliczności.
Upraszczając, oznacza to po prostu, że każdy pojedynczy znak w ciągu może być łatwo obsługiwany jako część sekwencyjnego układu elementów, podobnie jak tablice w innych językach programowania.
Aby zrozumieć, jak to działa, przejrzyj przykład 02, aby uzyskać dobry przegląd.
### 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'
Ładunek poznawczy związany ze zrozumieniem, jak działa w notacji plasterka python rzeczywiście mogą być zbyt wiele dla niektórych podmiotów przyjmujących i programistów, którzy nie chcą inwestować dużo czasu w nauce języka.
Niemniej jednak, po zrozumieniu podstawowych zasad, siła tego podejścia w stosunku do ustalonych metod manipulacji strunami może być całkiem korzystna.
Dla tych, którzy myślą inaczej, istnieją alternatywne podejścia, takie jak funkcje lambda, iteratory lub proste deklaracje funkcji jednorazowych.
W razie potrzeby programista może wdrożyć własną metodę string.reverse (), jednak dobrze jest zrozumieć uzasadnienie tego aspektu python.
Istniejące odpowiedzi są poprawne tylko wtedy, gdy ignorowane są modyfikatory Unicode / klastry grafemów. Zajmę się tym później, ale najpierw przyjrzyjmy się prędkości niektórych algorytmów odwracania:
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
Widać, że czas na zrozumienie listy ( reversed = string[::-1]) jest we wszystkich przypadkach zdecydowanie najniższy (nawet po poprawieniu mojej literówki).
Jeśli naprawdę chcesz odwrócić ciąg znaków w zdrowym znaczeniu, jest to DROGA bardziej skomplikowane. Na przykład weź następujący ciąg ( brązowy palec skierowany w lewo , żółty palec skierowany w górę ). To są dwa grafemy, ale 3 punkty kodu Unicode. Dodatkowym jest modyfikator skórki .
example = "👈🏾👆"
Ale jeśli odwrócisz jedną z podanych metod, dostaniesz brązowy palec skierowany w górę , żółty palec skierowany w lewo . Powodem tego jest to, że „brązowy” modyfikator koloru jest nadal na środku i jest stosowany do wszystkiego, co jest przed nim. Więc mamy
i
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
Klastry Grapheme Unicode są nieco bardziej skomplikowane niż tylko punkty kodu modyfikatora. Na szczęście istnieje biblioteka do obsługi grafemów :
>>> import grapheme
>>> g = grapheme.graphemes("👈🏾👆")
>>> list(g)
['👈🏾', '👆']
i stąd poprawna odpowiedź byłaby
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
który również jest zdecydowanie najwolniejszy:
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. Np .:rev_string("abcdef"*1000)
Mniej kłopotliwym sposobem spojrzenia na to byłoby:
string = 'happy'
print(string)
'szczęśliwy'
string_reversed = string[-1::-1]
print(string_reversed)
„yppah”
W języku angielskim [-1 :: - 1] brzmi:
„Zaczynając od -1, przejdź całą drogę, wykonując kroki -1”
-1nadal jest to niepotrzebne.
Odwróć ciąg znaków w pythonie bez użycia reverse () lub [:: - 1]
def reverse(test):
n = len(test)
x=""
for i in range(n-1,-1,-1):
x += test[i]
return x
To także ciekawy sposób:
def reverse_words_1(s):
rev = ''
for i in range(len(s)):
j = ~i # equivalent to j = -(i + 1)
rev += s[j]
return rev
lub podobne:
def reverse_words_2(s):
rev = ''
for i in reversed(range(len(s)):
rev += s[i]
return rev
Kolejny bardziej „egzotyczny” sposób użycia byterarray, który obsługuje .reverse ()
b = bytearray('Reverse this!', 'UTF-8')
b.reverse()
b.decode('UTF-8')
będzie produkować:
'!siht esreveR'
def reverse(input):
return reduce(lambda x,y : y+x, input)
original = "string"
rev_index = original[::-1]
rev_func = list(reversed(list(original))) #nsfw
print(original)
print(rev_index)
print(''.join(rev_func))
def reverse_string(string):
length = len(string)
temp = ''
for i in range(length):
temp += string[length - i - 1]
return temp
print(reverse_string('foo')) #prints "oof"
Działa to poprzez zapętlanie łańcucha i przypisywanie jego wartości w odwrotnej kolejności do innego łańcucha.
Oto wymyślny:
def reverse(text):
r_text = ''
index = len(text) - 1
while index >= 0:
r_text += text[index] #string canbe concatenated
index -= 1
return r_text
print reverse("hello, world!")
Oto jeden bez [::-1]lub reversed(do celów uczenia się):
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")
możesz użyć +=do konkatenacji ciągów, ale join()jest on szybszy.
Wszystkie powyższe rozwiązania są idealne, ale jeśli próbujemy odwrócić ciąg za pomocą pętli for w pythonie, będzie to nieco trudne, więc oto jak możemy odwrócić ciąg za pomocą pętli
string ="hello,world"
for i in range(-1,-len(string)-1,-1):
print (string[i],end=(" "))
Mam nadzieję, że ten będzie dla kogoś pomocny.
Istnieje wiele sposobów na odwrócenie łańcucha, ale stworzyłem też inny dla zabawy. Myślę, że to podejście nie jest takie złe.
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"))
Ta klasa używa magicznych funkcji Pythona do odwracania łańcucha:
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
W Pythonie 3 możesz odwrócić ciąg w miejscu, co oznacza, że nie zostanie on przypisany do innej zmiennej. Najpierw musisz przekonwertować ciąg na listę, a następnie użyć reverse()funkcji.
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()
Jest to prosta i znacząca funkcja odwrotna, łatwa do zrozumienia i kodowania
def reverse_sentence(text):
words = text.split(" ")
reverse =""
for word in reversed(words):
reverse += word+ " "
return reverse
Oto po prostu:
drukuj „loremipsum” [- 1 :: - 1]
a niektóre logicznie:
def str_reverse_fun():
empty_list = []
new_str = 'loremipsum'
index = len(new_str)
while index:
index = index - 1
empty_list.append(new_str[index])
return ''.join(empty_list)
print str_reverse_fun()
wynik:
muspimerol
Odwróć ciąg bez magii pytona.
>>> def reversest(st):
a=len(st)-1
for i in st:
print(st[a],end="")
a=a-1
Jasne, w Pythonie możesz robić bardzo fantazyjne 1-liniowe rzeczy. :)
Oto proste, wszechstronne rozwiązanie, które może działać w dowolnym języku programowania.
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)
Możesz użyć funkcji odwróconej z pełną listą. Ale nie rozumiem, dlaczego ta metoda została wyeliminowana w Pythonie 3, była niepotrzebnie.
string = [ char for char in reversed(string)]
.joinczegoś lub czegoś, aby była to poprawna odpowiedź
[c for c in string]jest równoznaczne z list(string).