文字列を特定の長さで繰り返す効率的な方法は何ですか?例:repeat('abc', 7) -> 'abcabca'
ここに私の現在のコードがあります:
def repeat(string, length):
cur, old = 1, string
while len(string) < length:
string += old[cur-1]
cur = (cur+1)%len(old)
return string
これを行うためのより良い(よりPython的な)方法はありますか?たぶんリストの内包表記を使用していますか?
def repeat_to_length(string_to_expand, length):
return (string_to_expand * ((length/len(string_to_expand))+1))[:length]
Python3の場合:
def repeat_to_length(string_to_expand, length):
return (string_to_expand * (int(length/len(string_to_expand))+1))[:length]
Jason Scheirerの答えは正しいが、もう少し説明が必要かもしれない。
まず、文字列を整数回繰り返すには、オーバーロードされた乗算を使用できます。
>>> 'abc' * 7
'abcabcabcabcabcabcabc'
したがって、必要な長さだけ少なくともになるまで文字列を繰り返すには、適切な繰り返し数を計算し、右側に配置します-その乗算演算子の手元:
def repeat_to_at_least_length(s, wanted):
return s * (wanted//len(s) + 1)
>>> repeat_to_at_least_length('abc', 7)
'abcabcabc'
次に、配列スライスを使用して、必要な正確な長さにトリミングできます。
def repeat_to_length(s, wanted):
return (s * (wanted//len(s) + 1))[:wanted]
>>> repeat_to_length('abc', 7)
'abcabca'
あるいは、 pillmodの答え で提案されているように、おそらく誰ももうスクロールするほどスクロールしないので、 divmod
を使用して、必要な完全な繰り返しの数と余分な数を計算できます文字、すべて一度に:
def pillmod_repeat_to_length(s, wanted):
a, b = divmod(wanted, len(s))
return s * a + s[:b]
どちらが良いですか?ベンチマークしましょう:
>>> import timeit
>>> timeit.repeat('scheirer_repeat_to_length("abcdefg", 129)', globals=globals())
[0.3964178159367293, 0.32557755894958973, 0.32851039397064596]
>>> timeit.repeat('pillmod_repeat_to_length("abcdefg", 129)', globals=globals())
[0.5276265419088304, 0.46511475392617285, 0.46291469305288047]
だから、pillmodのバージョンは40%遅いようなもので、個人的にはもっと読みやすいと思うので、あまりにも悪いです。これには、いくつかの理由が考えられます。まず、バイトコード命令を約40%増やしてコンパイルします。
注:これらの例では、整数の除算を切り捨てるのにnew-ish //
演算子を使用しています。これはしばしばと呼ばれるPython 3機能ですが、 PEP 238 によれば、すべて導入されましたPython 2.2に戻ります。使用できるのはhavePython 3(またはfrom __future__ import division
を含むモジュール)で使用することだけですが、can関係なく使用できます。
これはかなりPythonicです。
newstring = 'abc'*5
print newstring[0:6]
def rep(s, m):
a, b = divmod(m, len(s))
return s * a + s[:b]
from itertools import cycle, islice
def srepeat(string, n):
return ''.join(islice(cycle(string), n))
おそらく最も効率的なソリューションではありませんが、確かに短く簡単です:
def repstr(string, length):
return (string * length)[0:length]
repstr("foobar", 14)
「foobarfoobarfo」を提供します。このバージョンの1つのことは、長さ<len(string)の場合、出力文字列が切り捨てられることです。例えば:
repstr("foobar", 3)
「foo」を提供します。
編集:実際には驚いたことに、これは現在受け入れられているソリューション(「repeat_to_length」関数)よりも速く、少なくとも短い文字列では:
from timeit import Timer
t1 = Timer("repstr('foofoo', 30)", 'from __main__ import repstr')
t2 = Timer("repeat_to_length('foofoo', 30)", 'from __main__ import repeat_to_length')
t1.timeit() # gives ~0.35 secs
t2.timeit() # gives ~0.43 secs
おそらく、文字列が長い場合、または長さが非常に長い場合(つまり、string * length
部分の無駄が多い場合)、パフォーマンスが低下します。実際、上記を変更してこれを検証できます。
from timeit import Timer
t1 = Timer("repstr('foofoo' * 10, 3000)", 'from __main__ import repstr')
t2 = Timer("repeat_to_length('foofoo' * 10, 3000)", 'from __main__ import repeat_to_length')
t1.timeit() # gives ~18.85 secs
t2.timeit() # gives ~1.13 secs
string * (length / len(string)) + string[0:(length % len(string))]
はどうですか
私はこれを使用します:
def extend_string(s, l):
return (s*l)[:l]
この質問に対する十分な答えがなかったわけではありませんが、繰り返し機能があります。リストを作成してから出力を結合するだけです:
from itertools import repeat
def rep(s,n):
''.join(list(repeat(s,n))
はい再帰!
def trunc(s,l):
if l > 0:
return s[:l] + trunc(s, l - len(s))
return ''
永遠にスケーリングすることはありませんが、小さい文字列には適しています。そしてそれはきれいです。
Little Schemerを読んだばかりで、今は再帰が好きだと認めています。
これはリスト内包表記を使用して行う方法の1つですが、rpt
文字列の長さが長くなるにつれて無駄になります。
def repeat(rpt, length):
return ''.join([rpt for x in range(0, (len(rpt) % length))])[:length]
別のFPアプローチ:
def repeat_string(string_to_repeat, repetitions):
return ''.join([ string_to_repeat for n in range(repetitions)])