文字列を特定の長さに繰り返す


204

文字列を特定の長さに繰り返す効率的な方法は何ですか?例えば: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

これを行うためのより良い(よりpythonicな)方法はありますか?おそらくリスト内包表記を使用していますか?

回答:


73
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]

5
これは整数除算を利用しているようです。//Python 3にある必要はありませんか?または、を削除+1し、上限関数への明示的な呼び出しを使用するだけで十分です。また、注意:生成された文字列は、均等に分割されると実際には余分な繰り返しがあります。余分はスプライスによって切断されます。最初は混乱しました。
jpmc26 2013年

int()ここでは同じことを行いますが、//2つのコマンドではなく1つのコマンドで分割とフロアを行うため、顕微鏡的には高速になる可能性があります。
Doyousketch2

667

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でずっと導入されました。あなただけ持っているのPython 3(または持っているモジュール内でそれを使用することfrom __future__ import division)ができますが、できる関わらず、それを使用しています。


8
いいえ、OPは結果が長さ7(3の倍数ではない)であることを望んでいます。
IanS 2017年

1
私は...これはOPの正しい答えではないですが、私と489他の人のための正しい答えであるため、ビットが衝突してる
マット・フレッチャー

2
@MattFletcher「受け入れられた回答の説明者としてこれを書き直さなければならない」から「これ書き直します...」までの
境界線を越えたところ



14
from itertools import cycle, islice
def srepeat(string, n):
   return ''.join(islice(cycle(string), n))

これは、文字列を反復するだけの場合に使用します(その場合、結合は必要ありません)。Pythonライブラリに仕事を任せましょう。
18年

7

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

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

1
最大の最適化のために、入力と出力の長さに基づいて2つのバージョンの間にスイッチを追加できます。
Mad Physicist

6

いかがですか string * (length / len(string)) + string[0:(length % len(string))]


length / len(string)括弧で囲む必要があり、最後のがありません]
MikeWyatt 2010

1
私の意見では、これまでで最も読みやすく/直感的です。//Python 3で整数除算を使用する必要があると思います0。スプライスのinはオプションです。(もちろん、コロンは必須です。)
jpmc26

6

私はこれを使います:

def extend_string(s, l):
    return (s*l)[:l]

5

この質問に対する十分な回答が得られたわけではありませんが、繰り返し機能があります。リストを作成し、出力に参加するだけです:

from itertools import repeat

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

これは質問の答えにはなりません。これは文字列をX回繰り返しますが、Xの長さになるまで繰り返されません。例えば"abc", 4期待するでしょう"abca"。これは作成されますabcabcabcabc
Marcus Lind

3

やった再帰!

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

いつまでも拡大縮小されることはありませんが、小さい文字列の場合は問題ありません。そして、それはきれいです。

Little Schemerを読んだばかりで、今は再帰が好きです。


1

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

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


0
def extended_string (word, length) :

    extra_long_word = word * (length//len(word) + 1)
    required_string = extra_long_word[:length]
    return required_string

print(extended_string("abc", 7))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.