Seite 1 von 2
Strings nach Länge zerteilen
Verfasst: Montag 3. Februar 2003, 16:32
von joerg
Hallo,
ich suche eine elegante Möglichkeit, einen String (s) in eine Liste von Einzelstrings aufzuspalten, die jeweils eine bestimmte
Länge (size) nicht überschreiten dürfen.
Momentan mache ich es so:
Code: Alles auswählen
def split(s, size):
n = int(len(s) / size)
l = map(lambda i: s[size*i:size*(i+1)], xrange(n))
if len(s) % size:
l.append(s[n*size:])
return l
Aber irgendwie habe ich das Gefühl, daß das viel kürzer und effizienter gehen muß.
Vorschläge?
Danke
Jörg
Verfasst: Montag 3. Februar 2003, 17:51
von Milan
nimms doch einfach so:
Code: Alles auswählen
def split(s, size):
return map(lambda i: s[i:i+size], xrange(0,len(s),size))
oder:
Code: Alles auswählen
split=lambda s,size: map(lambda i: s[i:i+size], xrange(0,len(s),size))
damit sparst du dir die zusätzliche Variablenbelegung und die If-Schleife
Verfasst: Montag 3. Februar 2003, 18:48
von Milan
wegen Sache Effizienz, ich hab mal wieder nen Geschwindigkeitstest gemacht:
Code: Alles auswählen
import time
def split(s, size):
n = int(len(s) / size)
l = map(lambda i: s[size*i:size*(i+1)], xrange(n))
if len(s) % size:
l.append(s[n*size:])
return l
def split2(s, size):
return map(lambda i: s[i:i+size], xrange(0,len(s),size))
def test(st,si,num=10):
for i in xrange(num):
t1=time.clock()
split(st,si)
t2=time.clock()
split2(st,si)
t3=time.clock()
print t2-t1,t3-t2,(t3-t2)/(t2-t1)
a='a'*500000
test(a,3,10)
Die Ergebnisse sind:
Code: Alles auswählen
0.565693125802 0.470296085117 0.83136255978
0.572923094974 0.482870588301 0.842819206516
0.594853256489 0.481883311985 0.810087709411
0.588265827081 0.489244582761 0.831672621863
0.596176888403 0.480837368995 0.806534735493
0.578952073518 0.477834194011 0.825343263921
0.588023617527 0.46635117033 0.793082380418
0.581662753227 0.48646769352 0.836339770461
0.57838691789 0.467634014938 0.808514163224
0.574977825394 0.482925343864 0.83990255369
das bedeutet ca. 20 % Ersparniss, ich denke aber das sich das noch weiter steigern ließe...
Verfasst: Dienstag 4. Februar 2003, 09:50
von joerg
Milan hat geschrieben:
Code: Alles auswählen
split=lambda s,size: map(lambda i: s[i:i+size], xrange(0,len(s),size))
damit sparst du dir die zusätzliche Variablenbelegung und die If-Schleife
Genial! An so etwas hatte ich gedacht.
Und 20% mehr Speed nimmt man ja gerne mit.

Danke!
Jörg
Verfasst: Mittwoch 16. Juli 2008, 12:03
von ete
Hallo!
Kann man auch mehrere strings syncron teilen?
a = 20 * 'a'
b = 20 * 'b'
Das ganze soll dann so aussehen:
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
Verfasst: Mittwoch 16. Juli 2008, 12:15
von EyDu
Teil die Strings noch nacheinander und bringe sie dann in die richtige Reihenfolge. Vielleicht hilft dir auch die zip-Funktion weiter.
Milan hat geschrieben:damit sparst du dir die zusätzliche Variablenbelegung und die If-Schleife
http://www.if-schleife.de/ 
Verfasst: Mittwoch 16. Juli 2008, 12:36
von audax
ete hat geschrieben:Hallo!
Kann man auch mehrere strings syncron teilen?
a = 20 * 'a'
b = 20 * 'b'
Das ganze soll dann so aussehen:
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
Code: Alles auswählen
from itertools import izip
def split(s, size):
return (s[i:i+size] for i in xrange(0,len(s),size))
a= 'a'*50
b = 'b'*50
print [a+b for a,b in izip(split(a, 7), split(b, 7))]
['aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'ab']
Du hättest übrigens ruhig einen neuen Thread öffnen können anstatt die Leiche hervorzukramen.
Verfasst: Mittwoch 16. Juli 2008, 13:26
von ete
Danke für die Tips!
Ich dachte es passt hier gut...Naja, beim nächsten Mal.
Verfasst: Donnerstag 17. Juli 2008, 11:23
von da.dom
Milan hat geschrieben:nimms doch einfach so:
Code: Alles auswählen
def split(s, size):
return map(lambda i: s[i:i+size], xrange(0,len(s),size))
Kann mir das mal jemand Wort für Wort erklären was da genau gemacht wird

irgendwie kommeich mit dieser lambda Funktion immer noch nicht so ganz klar.
lambda i: > Lambda erzeugt mir ein Funktionsobjekt, i ist der Parameter? Woher kommt der?
s[i:i+size] > ok ich cutte den String
,xrange(0,len(s),size) > gibt mir eine Liste von Schnittpunkten zurück
passt das so? Aber wie kommt die lambda Funktion jetzt auf die Idee, sich mehrfach auf zu rufen (für jeden Cut einmal?) Und das der TeilString der erzeugt wird, ist automatisch der Return-Wert?
Danke schon mal

D
Verfasst: Donnerstag 17. Juli 2008, 11:40
von BlackJack
``lambda`` erzeugt einfach eine Funktion ohne sie an einen Namen zu binden. Als Funktions"körper" können nur Ausdrücke verwendet werden, die den Rückgabewert beschreiben. Man kann jedes Stück Quelltext mit ``lambda`` umschreiben, wenn man die Funktion vorher mit ``def`` definiert und ihr einen Namen gibt:
Code: Alles auswählen
def split(s, size):
# f = lambda i: s[i:i+size]
def f(i):
return s[i:i+size]
return map(f, xrange(0, len(s), size))
Weder `f` noch die ``lambda``-Funktion kommen auf die Idee sich selbst auf zu rufen, das macht `map()`.
Verfasst: Donnerstag 17. Juli 2008, 12:01
von da.dom
ok das macht die Sache klarer, aber:
Code: Alles auswählen
def split(s, size):
return lambda i: s[i:i+size], range(0,len(s),size)
die lambda Funktion hier nimmt einen Parameter an (i). map ruft die die lambda Funktion immer wieder auf, durch die Liste die aus der range() Funktion kommt (das "map" hatte ich ganz überlesen

): ok. Und die Map Funktion setzt für "i" die Elemte aus der range-Liste ein?
So richtig? *schnauf* wer soll denn durch die ganzen Funktionalitäten die Python anbietet durchblicken
D
PS: Und gleich noch eine Frage zu dem Thema hinterher:
Ich habe eine Liste von CutPoints, die ich abarbeiten will:
Code: Alles auswählen
def split(s, cutpoints):
return map(lambda i: s[0:i], cutpoints)
print split("Ich bin die Schlange", [3,6,9,20])
die
0 an der Stelle ist natürlich falsch, weil ich im Grunde da einen "Schrittzähler" haben müsste, der die quasi die aktuelle Position festhält...aber Zuweisungen mit = kann ich in der Lambda Funktion ja nicht machen

Verfasst: Donnerstag 17. Juli 2008, 12:25
von audax
Man muss nicht immer map() benutzen:
Code: Alles auswählen
def split(s, cutpoints):
off = 0
for point in cutpoints:
yield s[off:point]
off = point
print list(split("Ich bin die Schlange", [3,6,9,20]))
Verfasst: Donnerstag 17. Juli 2008, 12:45
von BlackJack
Och das ist mir viel zu imperativ.
Code: Alles auswählen
from functools import partial
from itertools import chain, imap, tee
from operator import getslice
def split(string, cutpoints):
cp_1, cp_2 = tee(cutpoints)
return imap(partial(getslice, string), chain([0], cp_1), cp_2)
def main():
print list(split('Ich bin die Schlange', [3, 6, 9, 20]))
if __name__ == '__main__':
main()
Verfasst: Donnerstag 17. Juli 2008, 12:47
von audax
Ich habs geschafft, zu widerstehen, so eine Lösung lag mir auch auf den Fingern

Nur hätte er damit quasi nix anfangen können
/me wantz compose() in der stdlib

Verfasst: Donnerstag 17. Juli 2008, 12:56
von da.dom
Jetzt wird es aber gruselig oder

? Ich hoffe das man das nicht verstehen muss

Verfasst: Donnerstag 17. Juli 2008, 14:05
von BlackJack
@audax: Ja `compose()` wäre nett.
@da.dom: Also ich find's nicht gruselig, sondern elegant. Funktionale Programmierung rockt!

Verfasst: Mittwoch 13. August 2008, 14:42
von ete
audax hat geschrieben:ete hat geschrieben:Hallo!
Kann man auch mehrere strings syncron teilen?
a = 20 * 'a'
b = 20 * 'b'
Das ganze soll dann so aussehen:
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
aaaaa
bbbbb
Code: Alles auswählen
from itertools import izip
def split(s, size):
return (s[i:i+size] for i in xrange(0,len(s),size))
a= 'a'*50
b = 'b'*50
print [a+b for a,b in izip(split(a, 7), split(b, 7))]
['aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'aaaaaaabbbbbbb', 'ab']
Du hättest übrigens ruhig einen neuen Thread öffnen können anstatt die Leiche hervorzukramen.
Funktioniert das auch wenn a aus meheren teil strings besteht, also
a = [20 * 'a', 20 * x]
b = 20 * 'b'
wobei es dann so gesplittet werden soll:
aaaaaaaaa
xxxxxxxxx
bbbbbbbbb
aaaaaaaaa
xxxxxxxxx
bbbbbbbbb
Verfasst: Mittwoch 13. August 2008, 20:59
von audax
Drück dich mal bitte genauer aus.
Wie willst du denn
gemeinsam splitten? Oo
Das eine ist eine Liste mit 2 Elementen, das andere ein String oO
Verfasst: Donnerstag 14. August 2008, 07:52
von ete
a = aaaaaaaaaaaaaaaaaaaa, xxxxxxxxxxxxxxxxxxx
b = bbbbbbbbbbbbbbbbbbb
Nach dem Splitten:
aaaaaaaaa
xxxxxxxxx
bbbbbbbbb
aaaaaaaaa
xxxxxxxxx
bbbbbbbbb
Edit:
Wobei es kein Tuple ist, wie ich gerade sehe:
liste3 = [[10, 11, 12, 15, 16, 17, 18, 19, 20, 21], [19, 20, 21, 22, 23], [20, 21, 22, 23, 24]]
for x in liste3:
print "".join(">" if y in x else "-" for y in range(30))
a = 50*'a'
b = 50*'b'
Soll ergeben:
30 mal a
30 mal b
30 mal alle strings von liste3
Rest von a (also 20)
Rest von b
Rest von allen strings von liste3
Verfasst: Donnerstag 14. August 2008, 09:07
von audax
30 mal alle strings von liste3
Häh?
Das sind keine Strings sondern Listen von Zahlen Oo
Mach doch mal nen konkretes Beispiel, mit kompletten Angaben,[/code]