web-dev-qa-db-fra.com

Répéter la chaîne à une certaine longueur

Quel est un moyen efficace de répéter une chaîne d'une certaine longueur? Par exemple: repeat('abc', 7) -> 'abcabca'

Voici mon code actuel:

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

Existe-t-il un meilleur moyen (plus pythonique) de le faire? Peut-être en utilisant la compréhension de liste?

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

Pour python3:

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

La réponse de Jason Scheirer est correcte, mais pourrait être plus détaillée.

Tout d'abord, pour répéter une chaîne un nombre entier de fois, vous pouvez utiliser une multiplication surchargée:

>>> 'abc' * 7
'abcabcabcabcabcabcabc'

Donc, pour répéter une chaîne jusqu'à ce que au moins aussi longtemps que vous le souhaitez, vous calculez le nombre approprié de répétitions et placez-le à droite. côté de cet opérateur de multiplication:

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

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

Ensuite, vous pouvez le couper à la longueur exacte souhaitée avec une tranche de tableau:

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

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

Alternativement, comme suggéré dans réponse de pillmod que personne ne fait probablement défiler l'écran assez loin pour le remarquer, vous pouvez utiliser divmod pour calculer le nombre de répétitions complètes nécessaires et le nombre de répétitions supplémentaires. caractères, tous à la fois:

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

Ce qui est mieux? Comparons cela:

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

Donc, la version de pillmod est 40% plus lente, ce qui est dommage, car personnellement, je pense que c'est beaucoup plus lisible. Il y a plusieurs raisons possibles à cela, à commencer par la compilation d’environ 40% d’instructions de bytecode supplémentaires.

Remarque: ces exemples utilisent l'opérateur new-ish // pour tronquer la division entière. Ceci est souvent appelé une fonctionnalité Python 3, mais selon PEP 238 , il a été introduit tous le chemin du retour dans Python 2.2. Vous avez seulement à l’utiliser dans Python 3 (ou dans les modules qui ont from __future__ import division) mais vous peut l'utiliser quand même.

614
zwol

C'est joli Pythonic:

newstring = 'abc'*5
print newstring[0:6]
53
Helen K
def rep(s, m):
    a, b = divmod(m, len(s))
    return s * a + s[:b]
32
pillmuncher
from itertools import cycle, islice
def srepeat(string, n):
   return ''.join(islice(cycle(string), n))
14
kennytm

Peut-être pas la solution la plus efficace, mais certainement courte et simple:

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

repstr("foobar", 14)

Donne "foobarfoobarfo". Une chose à propos de cette version est que si length <len (chaîne), la chaîne en sortie sera tronquée. Par exemple:

repstr("foobar", 3)

Donne "foo".

Edit: en fait à ma grande surprise, ceci est plus rapide que la solution actuellement acceptée (la fonction 'repeat_to_length'), du moins sur les chaînes courtes:

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

Vraisemblablement, si la chaîne était longue ou si sa longueur était très élevée (c’est-à-dire si le gaspillage de la partie string * length était élevé), les performances seraient médiocres. Et en fait, nous pouvons modifier ce qui précède pour vérifier ceci:

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
Adam Parkin

Que diriez-vous de string * (length / len(string)) + string[0:(length % len(string))]

6
murgatroid99

j'utilise ceci:

def extend_string(s, l):
    return (s*l)[:l]
6
김민준

Non pas qu'il n'y ait pas eu suffisamment de réponses à cette question, mais il y a une fonction de répétition; juste besoin de faire une liste de puis rejoindre la sortie:

from itertools import repeat

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

Yay récursion!

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

Ne sera pas évolutive pour toujours, mais c'est bien pour les petites chaînes. Et c'est joli.

J'avoue que je viens de lire le Petit Schemer et j'aime la récursion en ce moment.

3
Triptych

C'est une façon de le faire en utilisant une liste de compréhension, bien que cela soit de plus en plus inutile à mesure que la longueur de la chaîne rpt augmente.

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

Un autre FP aproach:

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