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 a
nie 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.
while
i 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”
-1
nadal 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)]
.join
czegoś lub czegoś, aby była to poprawna odpowiedź
[c for c in string]
jest równoznaczne z list(string)
.