Ripeti la stringa per una certa lunghezza


205

Qual è un modo efficace per ripetere una stringa per una certa lunghezza? Per esempio:repeat('abc', 7) -> 'abcabca'

Ecco il mio codice attuale:

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

C'è un modo migliore (più pitonico) per farlo? Forse usando la comprensione della lista?

Risposte:


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

Per python3:

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

5
Sembra che questo stia sfruttando la divisione intera. Non è necessario che sia //in Python 3? Oppure è +1sufficiente rilasciare e utilizzare una chiamata esplicita a una funzione soffitto. Inoltre, una nota: la stringa generata in realtà ha una ripetizione extra quando si divide uniformemente; l'extra viene tagliato dalla giuntura. Questo all'inizio mi ha confuso.
jpmc26,

int()fa la stessa cosa qui, ma sì, //potrebbe essere microscopicamente più veloce, perché fa la divisione e il pavimento in un comando invece di due.
Doyousketch2,

667

La risposta di Jason Scheirer è corretta ma potrebbe usare qualche altra esposizione.

Prima di tutto, per ripetere una stringa un numero intero di volte, è possibile utilizzare la moltiplicazione sovraccarica:

>>> 'abc' * 7
'abcabcabcabcabcabcabc'

Quindi, per ripetere una stringa fino a quando è lunga almeno quanto la lunghezza desiderata, calcoli il numero appropriato di ripetizioni e lo metti sul lato destro dell'operatore di moltiplicazione:

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

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

Quindi, puoi tagliarlo alla lunghezza esatta desiderata con una porzione di matrice:

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

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

In alternativa, come suggerito nella risposta di pillmod che probabilmente nessuno scorre più in basso abbastanza da notare più, puoi usare divmodper calcolare il numero di ripetizioni complete necessarie e il numero di caratteri extra, tutto in una volta:

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

Che è migliore? Facciamo un benchmark:

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

Quindi, la versione di pillmod è qualcosa di più lento del 40%, il che è un peccato, dal momento che personalmente penso che sia molto più leggibile. Ci sono diverse possibili ragioni per questo, a partire dalla sua compilazione per circa il 40% in più di istruzioni bytecode.

Nota: questi esempi utilizzano l' //operatore new-ish per troncare la divisione di numeri interi. Questa è spesso chiamata funzionalità Python 3, ma secondo PEP 238 , è stata introdotta in Python 2.2. È solo necessario per utilizzarlo in Python 3 (o in moduli che hanno from __future__ import division), ma si può utilizzare a prescindere.


8
No, OP vuole che il risultato sia di lunghezza 7 (che non è un multiplo di 3).
IanS

1
Sono un po 'in conflitto perché questa non è la risposta corretta per OP ma è la risposta corretta per me e altre 489 persone ...
Matt Fletcher

2
@MattFletcher Hai appena mi ha spinto oltre la linea da "dovrei riscrivere questo come un animatore della risposta accettato" a "Io voglio riscrivere questo ..." ;-)
Zwol

60

Questo è piuttosto pitonico:

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

14
0:7se vuoi 7 caratteri come OP.
Fisico pazzo,


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

Questo è quello che uso quando ho solo bisogno di scorrere la stringa (non è necessario alcun join). Lascia che le librerie Python facciano il lavoro.
wihlke,

7

Forse non è la soluzione più efficiente, ma sicuramente breve e semplice:

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

repstr("foobar", 14)

Fornisce "foobarfoobarfo". Una cosa di questa versione è che se la lunghezza <len (stringa) allora la stringa di output verrà troncata. Per esempio:

repstr("foobar", 3)

Dà "pippo".

Modifica: in realtà con mia sorpresa, questo è più veloce della soluzione attualmente accettata (la funzione 'repeat_to_length'), almeno su stringhe brevi:

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

Presumibilmente se la stringa fosse lunga o la lunghezza fosse molto alta (ovvero, se lo spreco della string * lengthparte fosse alto), avrebbe prestazioni scarse. E infatti possiamo modificare quanto sopra per verificarlo:

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
È possibile aggiungere un passaggio tra le due versioni in base alle lunghezze di input e output per la massima ottimizzazione.
Fisico pazzo,

6

Che ne dite di string * (length / len(string)) + string[0:(length % len(string))]


length / len(string)deve essere racchiuso tra parentesi e ti manca l'ultimo ].
MikeWyatt,

1
Il più leggibile / intuitivo finora, secondo me. Penso che devi usare //per la divisione dei numeri interi in Python 3. La 0giuntura è facoltativa. (I due punti sono richiesti, ovviamente.)
jpmc26

6

io uso questo:

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

5

Non che non ci siano state abbastanza risposte a questa domanda, ma c'è una funzione di ripetizione; ho solo bisogno di fare un elenco e quindi unire l'output:

from itertools import repeat

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

Questo non risponde alla domanda. Questo ripete la stringa X volte, non la ripete fino alla lunghezza X. Ad esempio "abc", 4, ci si aspetterebbe "abca". Ciò creerebbeabcabcabcabc
Marcus Lind il

3

Yay ricorsione!

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

Non si ridimensionerà per sempre, ma va bene per stringhe più piccole. Ed è carino.

Ammetto di aver appena letto il piccolo Schemer e mi piace la ricorsione in questo momento.


1

Questo è un modo per farlo usando una comprensione dell'elenco, sebbene sia sempre più dispendioso all'aumentare della lunghezza della rptstringa.

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

0

Un altro approccio FP:

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

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.