Повторіть рядок до певної довжини


204

Який ефективний спосіб повторити рядок до певної довжини? Наприклад: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

Чи є кращий (більш пітонічний) спосіб зробити це? Можливо, використовуючи розуміння списку?

Відповіді:


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

5
Схоже, це скористається цілим діленням. Хіба це не повинно бути //в Python 3? Або скасування +1та використання явного дзвінка до функції стелі буде достатньо. Також зауважте: створена рядок насправді має додаткове повторення, коли вона ділиться рівномірно; зайвий відрізається зрощенням. Це спочатку мене збентежило.
jpmc26

int()робить те саме, що тут, але так, //може бути мікроскопічно швидше, оскільки це ділить і підлогу в одній команді замість двох.
Doyousketch2

667

Відповідь Джейсона Шейрера правильна, але може використати ще одне викладення.

Спочатку, щоб повторити рядок цілим числом разів, ви можете використовувати перевантажене множення:

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

Отже, версія таблетки - це щось на кшталт 40% повільніше, що занадто погано, оскільки особисто я думаю, що це набагато читабельніше. Для цього є кілька можливих причин, починаючи з його складання приблизно до 40% більше інструкцій щодо байт-коду.

Примітка: у цих прикладах використовується //оператор new-ish для обрізання цілого поділу. Це часто називають функцією Python 3, але згідно з PEP 238 , вона була впроваджена ще в Python 2.2. Ви тільки повинні використовувати його в Python 3 (або в модулях , які мають from __future__ import division) , але ви можете використовувати його в будь-якому випадку .


8
Ні, ОП хоче, щоб результат був довжиною 7 (що не кратно 3).
ЯнС

1
Я трохи конфліктую, тому що це не правильна відповідь для ОП, але це правильна відповідь для мене та 489 інших людей ...
Метт Флетчер

2
@MattFletcher Ви тільки що штовхнули мене на лінії від «Я повинен переписати це як пояснюють прийнятий відповідь» на «я буду переписати ...» ;-)
zwol



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

Це те, що я використовую, коли мені потрібно лише перебирати рядок (жодне з'єднання тоді не потрібно). Нехай бібліотеки python виконують цю роботу.
wihlke

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

1
Ви можете додати перемикач між двома версіями на основі вхідних та вихідних довжин для максимальної оптимізації.
Божевільний фізик

6

Як щодо string * (length / len(string)) + string[0:(length % len(string))]


length / len(string)потрібно загорнути в круглі дужки, а ви пропускаєте останню ].
MikeWyatt

1
На мій погляд, найбільш читабельна / інтуїтивна поки що. Я думаю, що вам потрібно використовувати //для цілого поділу в Python 3. У 0зрощенні необов'язково. (
Товста


5

Не те, що на це питання недостатньо відповідей, але є функція повторення; просто потрібно скласти список, а потім приєднатися до виводу:

from itertools import repeat

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

Це не дає відповіді на запитання. Цей повторюємо рядок X разів, він не повторюється до X довжини. Наприклад "abc", 4, очікували б "abca". Це створило бabcabcabcabc
Маркус Лінд

3

Так, рекурсія!

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

Не буде масштабуватися назавжди, але це чудово для менших струн. І це досить.

Зізнаюся, я щойно прочитав Маленького Схемера і мені зараз подобається рекурсія.


1

Це один із способів зробити це за допомогою розуміння списку, хоча він стає все більш марним, оскільки довжина rptрядка збільшується.

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


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))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.