Pythonのreverse
オブジェクトには組み込みのstr
関数はありません。この方法を実装するための最良の方法は何ですか?
非常に簡潔な答えを提供するならば、その効率について詳しく述べてください。たとえば、str
オブジェクトが別のオブジェクトに変換されるかどうかなどです。
どうですか?
>>> 'hello world'[::-1]
'dlrow olleh'
これは 拡張スライス 構文です。これは[begin:end:step]
を実行することで動作します - beginとendをオフのままにして-1のステップを指定することで、文字列を反転します。
@ Paoloのs[::-1]
が最速です。もっと遅いアプローチ(もっと読みやすいかもしれませんが議論の余地があります)は''.join(reversed(s))
です。
文字列の逆関数を実装する最良の方法は何ですか?
この質問に対する私自身の経験は学術的です。ただし、簡単な答えを探しているプロの場合は、-1
ずつ進むスライスを使用してください。
>>> 'a string'[::-1]
'gnirts a'
またはより読みやすい(ただし、メソッド名の検索と、反復子を指定するとjoinがリストを形成するという事実のために遅くなります)、str.join
:
>>> ''.join(reversed('a string'))
'gnirts a'
または、読みやすさと再利用性のために、スライスを関数に入れます
def reversed_string(a_string):
return a_string[::-1]
その後:
>>> reversed_string('a_string')
'gnirts_a'
学術博覧会に興味がある場合は、読み続けてください。
Pythonのstrオブジェクトには組み込みのリバース関数はありません。
Pythonの文字列について知っておくべきことがいくつかあります。
Pythonでは、文字列は不変です。文字列を変更しても、文字列は変更されません。新しいものを作成します。
文字列はスライス可能です。文字列をスライスすると、指定された増分で、文字列内のあるポイントから後方または前方に、別のポイントに新しい文字列が得られます。スライス表記または下付き文字のスライスオブジェクトを使用します。
string[subscript]
下付き文字は、中括弧内にコロンを含めることでスライスを作成します。
string[start:stop:step]
ブレースの外側にスライスを作成するには、スライスオブジェクトを作成する必要があります。
slice_obj = slice(start, stop, step)
string[slice_obj]
''.join(reversed('foo'))
は読み取り可能ですが、別の呼び出された関数で文字列メソッドstr.join
を呼び出す必要があります。これを関数に入れましょう-それに戻ります:
def reverse_string_readable_answer(string):
return ''.join(reversed(string))
逆スライスを使用すると、はるかに高速になります。
'foo'[::-1]
しかし、スライスや原作者の意図にあまり詳しくない人にとって、これをどのように読みやすく理解しやすいものにすることができますか?添え字表記の外側にスライスオブジェクトを作成し、わかりやすい名前を付けて、添え字表記に渡します。
start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]
これを関数として実際に実装するには、単に説明的な名前を使用するだけで十分にセマンティックに明確だと思います。
def reversed_string(a_string):
return a_string[::-1]
そして、使い方は単純です:
reversed_string('foo')
インストラクターがいる場合、おそらく空の文字列から始めて、古い文字列から新しい文字列を作成することを望んでいます。 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
文字列は不変であるため、これは理論的に悪いです-new_string
に文字を追加しているように見えるたびに、理論的には毎回新しい文字列を作成しています!ただし、CPythonは特定のケースでこれを最適化する方法を知っています。
理論的には、部分文字列をリストに収集し、後で結合することをお勧めします。
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)
ただし、以下のCPythonのタイミングで見るように、CPythonは文字列の連結を最適化できるため、実際にはこれに時間がかかります。
タイミングは次のとおりです。
>>> 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は文字列の連結を最適化しますが、他の実装では ない場合があります :
... a + = bまたはa = a + bの形式のステートメントに対するCPythonのインプレース文字列連結の効率的な実装に依存しないでください。この最適化はCPythonでも脆弱で(一部のタイプでのみ機能します)、refcountingを使用しない実装ではまったく存在しません。ライブラリのパフォーマンスに敏感な部分では、代わりに '' .join()形式を使用する必要があります。これにより、さまざまな実装で線形時間で連結が発生します。
### example01 -------------------
mystring = 'coup_ate_grouping'
backwards = mystring[::-1]
print backwards
### ... or even ...
mystring = 'coup_ate_grouping'[::-1]
print mystring
### result01 -------------------
'''
gnipuorg_eta_puoc
'''
この回答は、@odigityからの以下の懸念に対処するために提供されています。
ワオ。私は最初、パオロが提案した解決策に恐怖を感じましたが、が最初のコメントを読んだときに感じた恐怖を後退させました。そのような明るいコミュニティは、とても基本的なのような暗号化された方法を使用することをお勧めします。どうしてs.reverse()じゃないの?
string.reverse()
のようなものを期待するかもしれませんstring.reverse()
を実装したくなるかもしれません。print 'coup_ate_grouping'[-4:] ## => 'ping'
print 'coup_ate_grouping'[-4:-1] ## => 'pin'
print 'coup_ate_grouping'[-1] ## => 'g'
[-1]
のインデックス作成のさまざまな結果により、一部の開発者が見逃される可能性があります。Pythonには特別な事情があります。文字列は iterable 型です。
string.reverse()
メソッドを排除するための1つの論理的根拠は、python開発者にこの特別な状況の力を利用する動機付けを与えることです。
簡単に言うと、これは単に、他のプログラミング言語の配列と同じように、文字列内の個々の文字を要素の順次配列の一部として簡単に操作できることを意味します。
これがどのように機能するかを理解するために、example02を検討することは良い概観を提供することができます。
### 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'
スライス記法がPythonでどのように機能するかを理解することに関連する 認知的負荷 は、実際には言語の学習に多くの時間を費やすことを望まない一部の採用者および開発者にとっては多すぎるかもしれません。
それにもかかわらず、いったん基本原理が理解されれば、固定文字列操作方法に対するこのアプローチの力は非常に有利になり得る。
そうではないと考える人には、ラムダ関数、イテレータ、単純な1回限りの関数宣言など、別の方法があります。
望むなら、開発者は自分自身のstring.reverse()メソッドを実装することができますが、pythonのこの側面の背後にある理論的根拠を理解するのは良いことです。
それを見るためのより厄介な方法は次のとおりです。
string = 'happy'
print(string)
'ハッピー'
string_reversed = string[-1::-1]
print(string_reversed)
イッパ
英語の場合、[-1 :: - 1]は次のようになります。
"-1から始めて、-1のステップを踏んで、ずっと走りなさい"
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])
Backward()または[:: - 1]を使用せずにpythonで文字列を反転
def reverse(test):
n = len(test)
x=""
for i in range(n-1,-1,-1):
x += test[i]
return x
def reverse(input):
return reduce(lambda x,y : y+x, input)
これもまた興味深い方法です。
def reverse_words_1(s):
rev = ''
for i in range(len(s)):
j = ~i # equivalent to j = -(i + 1)
rev += s[j]
return rev
または類似:
def reverse_words_2(s):
rev = ''
for i in reversed(range(len(s)):
rev += s[i]
return rev
.reverse()をサポートするバイト配列を使用したもう1つのより「エキゾチックな」方法
b = byterarray('Reverse this!', 'UTF-8')
b.reverse()
b.decode('UTF-8')`
生成されます:
'!siht esreveR'
既存の答えは、Unicode Modifiers /書記素クラスタが無視された場合にのみ正しいものです。これについては後で説明しますが、最初にいくつかの逆転アルゴリズムの速度を見てみましょう。
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
リスト内包表記(reversed = string[::-1]
)の時間は、(私のタイプミスを修正した後でも)すべてのケースではるかに低いことがわかります。
もしあなたが本当に常識的に文字列を反転させたいのであれば、それはもっと複雑です。たとえば、次の文字列を取ります( 茶色の指が左を向く 、 黄色の指が上を向く )。これらは2つの書記素ですが、3つのUnicodeコードポイントです。追加のものは スキンモディファイア です。
example = "????????????"
しかし、与えられた方法のどれかでそれを逆にすると、 茶色の指が上を向く 、 黄色の指が左を向く となります。その理由は、「茶色」のカラーモディファイヤがまだ中間にあり、それ以前のものに適用されるためです。だから我々は持っています
そして
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
Unicodeの書記素クラスタ は単なる修飾子のコードポイントよりも少し複雑です。幸いなことに、 書記素 を処理するためのライブラリがあります。
>>> import grapheme
>>> g = grapheme.graphemes("????????????")
>>> list(g)
['????????', '????']
したがって、正しい答えは
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
これもはるかに遅いです。
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 __== '__main__':
main()
これは空想のないものです:
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!")
それが私のやり方だ:
def reverse_string(string):
character_list = []
for char in string:
character_list.append(char)
reversed_string = ""
for char in reversed(character_list):
reversed_string += char
return reversed_string
上記の解決法はすべて完璧ですが、Pythonでforループを使用して文字列を反転させようとすると、少しトリッキーになります。
string ="hello,world"
for i in range(-1,-len(string)-1,-1):
print (string[i],end=(" "))
これが誰かに役立つことを願っています。
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"
これは、文字列をループ処理し、その値を別の文字列と逆の順序で割り当てることによって機能します。
original = "string"
rev_index = original[::-1]
rev_func = list(reversed(list(original))) #nsfw
print(original)
print(rev_index)
print(''.join(rev_func))
文字列を逆にする方法はたくさんありますが、楽しみのために別の方法も作成しました。このアプローチはそれほど悪くないと思います。
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"))
再帰的な方法:
def reverse(s): return s[0] if len(s)==1 else s[len(s)-1] + reverse(s[0:len(s)-1])
例:
print(reverse("Hello!")) #!olleH
これは[::-1]
またはreversed
のないものです(学習目的)。
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")
+=
を使用して文字列を連結することはできますが、join()
は高速です。
Pythonの魔法なしで文字列を反転します。
>>> def reversest(st):
a=len(st)-1
for i in st:
print(st[a],end="")
a=a-1