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.