Повторить строку до определенной длины

Что такое эффективный способ повторения строки до определенной длины? Например: 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

Есть ли лучший (более питонический) способ сделать это? Возможно, используя понимание списка?

Ответ 1

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]

Ответ 2

Ответ Джейсона Шайрера верный, но мог бы использовать еще немного изложения.

Во-первых, чтобы повторить строку целое число раз, вы можете использовать перегруженное умножение:

>>> '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), но вы можете использовать его независимо.

Ответ 3

Это довольно pythonic:

newstring = 'abc'*5
print newstring[0:6]

Ответ 4

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

Ответ 5

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

Ответ 6

Как насчет string * (length / len(string)) + string[0:(length % len(string))]

Ответ 7

Возможно, это не самое эффективное решение, но, безусловно, короткое и простое:

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

repstr("foobar", 14)

Дает "foobarfoobarfo". Одна вещь об этой версии заключается в том, что если длина < 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

Ответ 8

Не то, чтобы ответа на этот вопрос было недостаточно, но есть функция повторения; просто нужно составить список и затем присоединиться к выходу:

from itertools import repeat

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

Ответ 9

i использую это:

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

Ответ 10

Рекурсия Yay!

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

Не будет масштабироваться вечно, но отлично подходит для небольших строк. И это довольно.

Я признаю, что я просто прочитал Little Schemer, и мне нравится рекурсия прямо сейчас.

Ответ 11

Это один из способов сделать это, используя понимание списка, хотя оно становится все более расточительным по мере увеличения длины строки rpt.

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

Ответ 12

Другой подход к FP:

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

Ответ 13

import numpy as np
''.join(np.array(10 * ["string"]).tolist())

Ответ 14

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