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/ :P

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

Code: Alles auswählen

f = lambda i,y: i+y
print f(3,5)
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

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 :D
Nur hätte er damit quasi nix anfangen können :o

/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 :D

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

Code: Alles auswählen

a = [20 * 'a', 20 * x]
b = 20 * 'b' 
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]