Strings nach Länge zerteilen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
joerg
User
Beiträge: 188
Registriert: Samstag 17. August 2002, 17:48
Wohnort: Berlin
Kontaktdaten:

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
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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...
Zuletzt geändert von Milan am Sonntag 9. Februar 2003, 10:14, insgesamt 1-mal geändert.
joerg
User
Beiträge: 188
Registriert: Samstag 17. August 2002, 17:48
Wohnort: Berlin
Kontaktdaten:

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
ete
User
Beiträge: 218
Registriert: Montag 19. Februar 2007, 13:19
Kontaktdaten:

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
http://www.snowflake-sl.info/index.html
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

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.
ete
User
Beiträge: 218
Registriert: Montag 19. Februar 2007, 13:19
Kontaktdaten:

Danke für die Tips!
Ich dachte es passt hier gut...Naja, beim nächsten Mal.
http://www.snowflake-sl.info/index.html
da.dom
User
Beiträge: 114
Registriert: Dienstag 10. Juni 2008, 14:42

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
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()`.
da.dom
User
Beiträge: 114
Registriert: Dienstag 10. Juni 2008, 14:42

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 :)
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

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]))
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()
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

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 :(
da.dom
User
Beiträge: 114
Registriert: Dienstag 10. Juni 2008, 14:42

Jetzt wird es aber gruselig oder :) ? Ich hoffe das man das nicht verstehen muss :D
BlackJack

@audax: Ja `compose()` wäre nett. :-)

@da.dom: Also ich find's nicht gruselig, sondern elegant. Funktionale Programmierung rockt! :-)
ete
User
Beiträge: 218
Registriert: Montag 19. Februar 2007, 13:19
Kontaktdaten:

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
http://www.snowflake-sl.info/index.html
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

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
ete
User
Beiträge: 218
Registriert: Montag 19. Februar 2007, 13:19
Kontaktdaten:

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
http://www.snowflake-sl.info/index.html
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

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