web-dev-qa-db-ja.com

特定の長さまで文字列を繰り返します

文字列を特定の長さで繰り返す効率的な方法は何ですか?例: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的な)方法はありますか?たぶんリストの内包表記を使用していますか?

173
John Howard
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]
61
Jason Scheirer

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関係なく使用できます。

595
zwol

これはかなりPythonicです。

newstring = 'abc'*5
print newstring[0:6]
53
Helen K
def rep(s, m):
    a, b = divmod(m, len(s))
    return s * a + s[:b]
32
pillmuncher
from itertools import cycle, islice
def srepeat(string, n):
   return ''.join(islice(cycle(string), n))
14
kennytm

おそらく最も効率的なソリューションではありませんが、確かに短く簡単です:

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
6
Adam Parkin

string * (length / len(string)) + string[0:(length % len(string))]はどうですか

6
murgatroid99

私はこれを使用します:

def extend_string(s, l):
    return (s*l)[:l]
6
김민준

この質問に対する十分な答えがなかったわけではありませんが、繰り返し機能があります。リストを作成してから出力を結合するだけです:

from itertools import repeat

def rep(s,n):
  ''.join(list(repeat(s,n))
5
Amy Platt

はい再帰!

def trunc(s,l):
    if l > 0:
        return s[:l] + trunc(s, l - len(s))
    return ''

永遠にスケーリングすることはありませんが、小さい文字列には適しています。そしてそれはきれいです。

Little Schemerを読んだばかりで、今は再帰が好きだと認めています。

3
Triptych

これはリスト内包表記を使用して行う方法の1つですが、rpt文字列の長さが長くなるにつれて無駄になります。

def repeat(rpt, length):
    return ''.join([rpt for x in range(0, (len(rpt) % length))])[:length]
1
vezult

別のFPアプローチ:

def repeat_string(string_to_repeat, repetitions):
    return ''.join([ string_to_repeat for n in range(repetitions)])
0
Aleš Kotnik