Повторите строку до определенной длины - PullRequest
175 голосов
/ 02 августа 2010

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

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

Ответы [ 13 ]

603 голосов
/ 02 августа 2010

Ответ Джейсона Шайрера верен, но может использовать еще несколько экспозиций.

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

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

62 голосов
/ 02 августа 2010
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]
53 голосов
/ 12 ноября 2013

Это довольно питонично:

newstring = 'abc'*5
print newstring[0:6]
32 голосов
/ 02 августа 2010
def rep(s, m):
    a, b = divmod(m, len(s))
    return s * a + s[:b]
14 голосов
/ 02 августа 2010
from itertools import cycle, islice
def srepeat(string, n):
   return ''.join(islice(cycle(string), n))
6 голосов
/ 12 сентября 2013

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

def extend_string(s, l):
    return (s*l)[:l]
6 голосов
/ 26 января 2012

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

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

repstr("foobar", 14)

Дает "foobarfoobarfo".Одна вещь в этой версии состоит в том, что если длина

repstr("foobar", 3)

Дает "foo".

Редактировать: фактически, к моему удивлению, это быстрее, чем принятое в настоящее время решение (функция repeat_to_length '), по крайней мере, на короткихstrings:

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
6 голосов
/ 02 августа 2010

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

5 голосов
/ 20 сентября 2012

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

from itertools import repeat

def rep(s,n):
  ''.join(list(repeat(s,n))
3 голосов
/ 02 августа 2010

Yay рекурсия!

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

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

Признаюсь, я только что прочитал Маленького Планировщика, и сейчас мне нравится рекурсия.

...