Repetir cadena a cierta longitud


¿Cuál es una forma eficiente de repetir una cadena a una longitud determinada? Por ejemplo: repeat('abc', 7) -> 'abcabca'

Aquí está mi código actual:

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

¿Hay una mejor manera (más pitónica) de hacer esto? ¿Tal vez usando la comprensión de la lista?

Author: John Howard, 2010-08-02

12 answers

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

Para python3:

def repeat_to_length(string_to_expand, length):
    return (string_to_expand * (int(length/len(string_to_expand))+1))[:length]
 53
Author: Jason Scheirer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-23 22:56:06

La respuesta de Jason Scheirer es correcta, pero podría necesitar más exposición.

En primer lugar, para repetir una cadena un número entero de veces, puede usar la multiplicación sobrecargada:

>>> 'abc' * 7
'abcabcabcabcabcabcabc'

Entonces, para repetir una cadena hasta que sea al menos tan larga como la longitud que desee, calcule el número apropiado de repeticiones y colóquela en el lado derecho de ese operador de multiplicación:

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

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

Luego, puede recortarlo a la longitud exacta que desee con una matriz slice:

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

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

Alternativamente, como se sugiere en la respuesta de pillmod que probablemente nadie se desplaza lo suficientemente lejos como para darse cuenta, puede usar divmod para calcular el número de repeticiones completas necesarias, y el número de caracteres adicionales, todo a la vez:

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

¿cuál es mejor? Vamos a compararlo:

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

Entonces, la versión de pillmod es algo así como un 40% más lenta, lo cual es una lástima, ya que personalmente creo que es mucho más legible. Hay varios posibles razones para esto, comenzando con su compilación a aproximadamente un 40% más de instrucciones de código de bytes.

Nota: estos ejemplos usan el operador new-ish // para truncar la división entera. A menudo se llamauna característica de Python 3, pero de acuerdo con PEP 238, se introdujo en Python 2.2. Solo tiene para usarlo en Python 3 (o en módulos que tienen from __future__ import division) pero puede usarlo independientemente.

 537
Author: zwol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-19 13:51:15

Esto es bastante pitónico:

newstring = 'abc'*5
print newstring[0:6]
 46
Author: Helen K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-12 16:45:49
def rep(s, m):
    a, b = divmod(m, len(s))
    return s * a + s[:b]
 31
Author: pillmuncher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-02 19:50:43
from itertools import cycle, islice
def srepeat(string, n):
   return ''.join(islice(cycle(string), n))
 14
Author: kennytm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-02 19:39:18

Yo uso esto:

def extend_string(s, l):
    return (s*l)[:l]
 6
Author: 김민준,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-12 11:11:06

Qué tal string * (length / len(string)) + string[0:(length % len(string))]

 5
Author: murgatroid99,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-02 19:36:32

Quizás no sea la solución más eficiente, pero ciertamente corta y simple:

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

repstr("foobar", 14)

Da "foobarfoobarfo". Una cosa acerca de esta versión es que si length

repstr("foobar", 3)

Da "foo".

Editar: en realidad para mi sorpresa, esto es más rápido que la solución actualmente aceptada (la función' repeat_to_length'), al menos en cadenas cortas:

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

Presumiblemente si la cadena era larga, o la longitud era muy alto (es decir, si el desperdicio de la parte string * length era alto), entonces funcionaría mal. Y de hecho podemos modificar lo anterior para verificar esto:

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
 5
Author: Adam Parkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-26 17:52:57

No es que no haya habido suficientes respuestas a esta pregunta, pero hay una función de repetición; solo hay que hacer una lista de y luego unir la salida:

from itertools import repeat

def rep(s,n):
  ''.join(list(repeat(s,n))
 5
Author: Amy Platt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-20 21:38:09

¡Yay recursión!

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

No escalará para siempre, pero está bien para cuerdas más pequeñas. Y es bonito.

Admito que acabo de leer el Pequeño Intrigante y me gusta la recursión en este momento.

 3
Author: Triptych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-02 19:55:10

Esta es una forma de hacerlo usando una comprensión de lista, aunque es cada vez más derrochadora a medida que aumenta la longitud de la cadena rpt.

def repeat(rpt, length):
    return ''.join([rpt for x in range(0, (len(rpt) % length))])[:length]
 1
Author: vezult,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-02 19:35:52

Otro enfoque de FP:

def repeat_string(string_to_repeat, repetitions):
    return ''.join([ string_to_repeat for n in range(repetitions)])
 0
Author: Aleš Kotnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-19 16:46:24