Wiederholen Sie die Zeichenfolge bis zu einer bestimmten Länge

204

Was ist ein effizienter Weg, um eine Zeichenfolge bis zu einer bestimmten Länge zu wiederholen? Z.B:repeat('abc', 7) -> 'abcabca'

Hier ist mein aktueller Code:

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

Gibt es einen besseren (pythonischeren) Weg, dies zu tun? Vielleicht mit Listenverständnis?

John Howard
quelle

Antworten:

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

Für Python3:

def repeat_to_length(string_to_expand, length):
    return (string_to_expand * (int(length/len(string_to_expand))+1))[:length]
Jason Scheirer
quelle
5
Sieht so aus, als würde dies die Ganzzahldivision ausnutzen. Muss das nicht //in Python 3 sein? Oder das Löschen +1und Verwenden eines expliziten Aufrufs einer Deckenfunktion würde ausreichen. Außerdem ein Hinweis: Die generierte Zeichenfolge hat tatsächlich eine zusätzliche Wiederholung, wenn sie gleichmäßig geteilt wird. Das Extra wird durch den Spleiß abgeschnitten. Das hat mich zuerst verwirrt.
jpmc26
int()macht hier das Gleiche, aber ja, //könnte mikroskopisch schneller sein, weil es die Teilung und den Boden in einem Befehl anstelle von zwei ausführt.
Doyousketch2
667

Die Antwort von Jason Scheirer ist richtig, könnte aber eine weitere Darstellung gebrauchen.

Um eine Zeichenfolge ganzzahlig zu wiederholen, können Sie zunächst die überladene Multiplikation verwenden:

>>> 'abc' * 7
'abcabcabcabcabcabcabc'

Um eine Zeichenfolge zu wiederholen, bis sie mindestens so lang ist wie die gewünschte Länge, berechnen Sie die entsprechende Anzahl von Wiederholungen und setzen sie auf die rechte Seite dieses Multiplikationsoperators:

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

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

Anschließend können Sie es mit einem Array-Slice auf die gewünschte Länge zuschneiden:

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

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

Alternativ können Sie, wie in der Antwort von pillmod vorgeschlagen , dass wahrscheinlich niemand mehr weit genug nach unten scrollt, um es zu bemerken, divmoddie Anzahl der erforderlichen vollständigen Wiederholungen und die Anzahl der zusätzlichen Zeichen gleichzeitig berechnen:

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

Welches ist besser? Lassen Sie es uns vergleichen:

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

Die Version von pillmod ist also ungefähr 40% langsamer, was schade ist, da ich persönlich denke, dass sie viel besser lesbar ist. Es gibt mehrere mögliche Gründe dafür, angefangen beim Kompilieren bis zu etwa 40% mehr Bytecode-Anweisungen.

Hinweis: In diesen Beispielen wird der //Operator new-ish zum Abschneiden der Ganzzahldivision verwendet. Dies wird oft als Python 3-Funktion bezeichnet, wurde jedoch laut PEP 238 bereits in Python 2.2 eingeführt. Sie müssen es nur in Python 3 (oder in Modulen mit from __future__ import division) verwenden, aber Sie können es trotzdem verwenden.

zwol
quelle
8
Nein, OP möchte, dass das Ergebnis die Länge 7 hat (was kein Vielfaches von 3 ist).
IanS
1
Ich bin ein bisschen in Konflikt geraten, weil dies nicht die richtige Antwort für OP ist, aber die richtige Antwort für mich und 489 andere Leute ...
Matt Fletcher
2
@ MattFletcher Sie haben mich gerade über die Linie von "Ich sollte dies als Erklärung der akzeptierten Antwort umschreiben " zu "Ich werde dies umschreiben ..."
geschoben ;-)
60

Das ist ziemlich pythonisch:

newstring = 'abc'*5
print newstring[0:6]
Helen K.
quelle
14
0:7wenn Sie 7 Zeichen wie OP wollen.
Mad Physicist
34
def rep(s, m):
    a, b = divmod(m, len(s))
    return s * a + s[:b]
Pillmuncher
quelle
14
from itertools import cycle, islice
def srepeat(string, n):
   return ''.join(islice(cycle(string), n))
kennytm
quelle
Dies ist, was ich verwende, wenn ich nur über die Zeichenfolge iterieren muss (dann ist kein Join erforderlich). Lassen Sie die Python-Bibliotheken den Job machen.
wihlke
7

Vielleicht nicht die effizienteste Lösung, aber sicherlich kurz und einfach:

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

repstr("foobar", 14)

Gibt "foobarfoobarfo". Eine Sache bei dieser Version ist, dass wenn die Länge <len (Zeichenfolge) ist, die Ausgabezeichenfolge abgeschnitten wird. Beispielsweise:

repstr("foobar", 3)

Gibt "foo".

Bearbeiten: Eigentlich ist dies zu meiner Überraschung schneller als die derzeit akzeptierte Lösung (die Funktion 'repeat_to_length'), zumindest bei kurzen Zeichenfolgen:

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

Vermutlich würde die Saite string * lengthschlecht funktionieren, wenn sie lang oder sehr lang wäre (dh wenn die Verschwendung des Teils hoch wäre). Und tatsächlich können wir das oben Gesagte ändern, um dies zu überprüfen:

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
Adam Parkin
quelle
1
Sie können einen Wechsel zwischen den beiden Versionen basierend auf den Eingabe- und Ausgabelängen hinzufügen, um eine maximale Optimierung zu erzielen.
Mad Physicist
6

Wie wäre es mit string * (length / len(string)) + string[0:(length % len(string))]

murgatroid99
quelle
length / len(string)muss in Klammern eingeschlossen sein, und Sie vermissen den letzten ].
MikeWyatt
1
Das bisher lesbarste / intuitivste, meiner Meinung nach. Ich denke, Sie müssen //für die Ganzzahldivision in Python 3 verwenden. Das 0im Spleiß ist optional. (Der Doppelpunkt ist natürlich erforderlich.)
jpmc26
6

ich benutze das:

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

Nicht, dass es nicht genügend Antworten auf diese Frage gegeben hätte, aber es gibt eine Wiederholungsfunktion. Sie müssen nur eine Liste erstellen und dann die Ausgabe verbinden:

from itertools import repeat

def rep(s,n):
  ''.join(list(repeat(s,n))
Amy Platt
quelle
Dies beantwortet die Frage nicht. Dieser wiederholt die Zeichenfolge X-mal, er wiederholt sie erst nach X-Länge. ZB "abc", 4würde erwarten "abca". Dies würde schaffenabcabcabcabc
Marcus Lind
3

Yay Rekursion!

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

Skaliert nicht für immer, ist aber für kleinere Saiten in Ordnung. Und es ist hübsch.

Ich gebe zu, ich habe gerade den kleinen Schemer gelesen und ich mag jetzt Rekursion.

Triptychon
quelle
1

Dies ist eine Möglichkeit, dies mithilfe eines Listenverständnisses zu tun, obwohl es mit zunehmender Länge der rptZeichenfolge zunehmend verschwenderisch wird .

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

Ein weiterer FP-Ansatz:

def repeat_string(string_to_repeat, repetitions):
    return ''.join([ string_to_repeat for n in range(repetitions)])
Aleš Kotnik
quelle
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))
Aditya Verma
quelle