Dizeyi belirli bir uzunlukta tekrarlayın


204

Bir dizeyi belirli bir uzunlukta tekrarlamanın etkili bir yolu nedir? Örneğin:repeat('abc', 7) -> 'abcabca'

İşte benim geçerli kod:

def repeat(string, length):
    cur, old = 1, string
    while len(string) < length:
        string += old[cur-1]
        cur = (cur+1)%len(old)
    return string

Bunu yapmanın daha iyi (daha pitonik) bir yolu var mı? Belki liste kavrayışı kullanıyor?

Yanıtlar:


73
def repeat_to_length(string_to_expand, length):
   return (string_to_expand * ((length/len(string_to_expand))+1))[:length]

Python3 için:

def repeat_to_length(string_to_expand, length):
    return (string_to_expand * (int(length/len(string_to_expand))+1))[:length]

5
Görünüşe göre bu tamsayı bölünmesinden yararlanıyor. Bunun //Python 3'te olması gerekmez mi? Veya +1bir tavan işlevine açık bir çağrı bırakmak ve kullanmak yeterli olacaktır. Ayrıca, bir not: oluşturulan dize eşit olarak bölündüğünde ek bir tekrarlamaya sahiptir; ekstra ek yeri tarafından kesilir. Bu beni ilk başta karıştırdı.
— jpmc26

int()burada aynı şeyi yapar, ancak evet, //mikroskopik olarak daha hızlı olabilir, çünkü bölme ve zemini iki yerine bir komutta yapar.
— Doyousketch2

667

Jason Scheirer'in cevabı doğrudur, ancak daha fazla açıklama yapabilir.

Öncelikle, bir dizeyi tamsayı kez tekrarlamak için aşırı yüklenmiş çarpmayı kullanabilirsiniz:

>>> 'abc' * 7
'abcabcabcabcabcabcabc'

Bu nedenle, bir dizeyi en az istediğiniz uzunlukta olana kadar tekrarlamak için , uygun tekrar sayısını hesaplar ve bu çarpma operatörünün sağ tarafına koyarsınız:

def repeat_to_at_least_length(s, wanted):
    return s * (wanted//len(s) + 1)

>>> repeat_to_at_least_length('abc', 7)
'abcabcabc'

Ardından, bir dizi dilimi ile tam olarak istediğiniz uzunluğa kırpabilirsiniz:

def repeat_to_length(s, wanted):
    return (s * (wanted//len(s) + 1))[:wanted]

>>> repeat_to_length('abc', 7)
'abcabca'

Alternatif olarak, pillmod'un cevabında önerildiği gibi , muhtemelen kimsenin artık fark etmeyecek kadar aşağıya kaymaması , divmodgereken tam tekrarların sayısını ve ekstra karakterlerin sayısını bir kerede hesaplamak için kullanabilirsiniz :

def pillmod_repeat_to_length(s, wanted):
    a, b = divmod(wanted, len(s))
    return s * a + s[:b]

Hangisi daha iyi? Bunu kıyaslayalım:

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

Yani, pillmod'un versiyonu% 40 daha yavaş bir şey, bu çok kötü, çünkü kişisel olarak çok daha okunabilir olduğunu düşünüyorum. Bunun yaklaşık% 40 daha fazla bayt kodu talimatı derlemesinden başlayarak bunun birkaç olası nedeni vardır.

Not: bu örnekler, //tamsayı bölünmesini kısaltmak için new-ish operatörünü kullanır. Buna genellikle Python 3 özelliği denir , ancak PEP 238'e göre , Python 2.2'ye kadar geri getirilmiştir. Yalnızca var Python 3'te (veya sahip modüllerde kullanmak için from __future__ import division), ancak olabilir ne olursa olsun kullanabilirsiniz.


8
Hayır, OP sonucun 7 uzunluğunda olmasını ister (bu, 3'ün katı değildir).
— IanS

1
Biraz çatıştım çünkü bu OP için doğru cevap değil ama benim ve diğer 489 kişi için doğru cevap ...
— Matt Fletcher

2
Sadece gelen hattı üzerinden beni itti ettik @MattFletcher "Ben "Ben kabul cevap bir explainer bu yeniden gerektiğini" olacak ;-) ... Bu yeniden"
— Zwol



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

Bu sadece dize üzerinde yineleme gerektiğinde kullandığım şeydir (o zaman birleştirmeye gerek yok). Bırakın python kütüphaneleri işi yapsın.
— wihlke

7

Belki de en etkili çözüm değil, ama kesinlikle kısa ve basit:

def repstr(string, length):
    return (string * length)[0:length]

repstr("foobar", 14)

"Foobarfoobarfo" verir. Bu sürümle ilgili bir şey, eğer uzunluk <len (string) ise çıktı dizesinin kısaltılmasıdır. Örneğin:

repstr("foobar", 3)

"Foo" verir.

Düzenleme: aslında benim için sürpriz, bu şu anda kabul edilen çözümden daha hızlıdır ('repeat_to_length' işlevi), en azından kısa dizelerde:

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

Muhtemelen dize uzunsa veya uzunluk çok yüksekse (yani, string * lengthparçanın israfı yüksekse), kötü performans gösterecektir. Aslında bunu doğrulamak için yukarıdakileri değiştirebiliriz:

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
Maksimum optimizasyon için giriş ve çıkış uzunluklarına bağlı olarak iki sürüm arasında bir anahtar ekleyebilirsiniz.
— Mad Physicist

6

Peki ya string * (length / len(string)) + string[0:(length % len(string))]


length / len(string)parantez içinde sarıcı olması gerekiyor ve sonuncusunu kaçırıyorsunuz ].
— MikeWyatt

1
Bence şimdiye kadarki en okunabilir / sezgisel. Sanırım //Python 3'te tamsayı bölme için kullanmanız gerekir. 0Ekte isteğe bağlıdır. (Tabii ki kolon gereklidir.)
— jpmc26 22

6

Bunu kullanıyorum:

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

5

Bu soruya yeterli cevap gelmediği için değil, tekrarlama işlevi var; sadece bir liste yapmak ve daha sonra çıktı katılmak gerekir:

from itertools import repeat

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

Bu soruya cevap vermiyor. Bu, dizeyi X kez tekrarlar, X uzunluğuna kadar tekrarlamaz. Örneğin "abc", 4beklenir "abca". Bu yaratacakabcabcabcabc
— Marcus Lind

3

Yay özyineleme!

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

Sonsuza dek ölçeklenmez, ancak daha küçük dizeler için iyidir. Ve güzel.

Küçük Schemer'i okuduğumu itiraf ediyorum ve şu anda özyinelemeyi seviyorum.


1

Bu bir liste kavrama kullanarak bunu yapmak için bir yoludur, ancak rptdize uzunluğu arttıkça giderek daha israf .

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

0

Başka bir FP yaklaşımı:

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

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))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.