Seite 1 von 1
StringField()-Alternative
Verfasst: 10.07.2017 11:38
von SBond
Hallo Leute,
mir ist gerade aufgefallen, dass StringField nicht gerade effizient arbeitet. Bei Verdoppelung der Einträge in einem String, halbiert sich die Anzahl der geparsten Einträge pro Sekunde. Somit vervierfacht sich die Zeit, in dem ein String (mit doppelt so vielen Einträgen) geparst wird.
Code: Alles auswählen
myString.s = ""
entries.i = 16000
For x = 1 To entries
myString + Str(x) + #CRLF$
Next
T1 = ElapsedMilliseconds()
For index = 1 To entries
selLine.s = StringField(myString, index, #CRLF$)
Next
T2 = ElapsedMilliseconds()
Debug "Dauer: " + Str(T2-T1) + " ms"
Debug "Eintäge: " + Str(entries)
Debug "Einträge pro Sek: " + StrD(entries/((T2-T1)/1000),2)
; Eintäge: 1000 - Einträge pro Sek: 27777.78
; Eintäge: 2000 - Einträge pro Sek: 14492.75
; Eintäge: 4000 - Einträge pro Sek: 7272.73
; Eintäge: 8000 - Einträge pro Sek: 3576.22
; Eintäge: 16000 - Einträge pro Sek: 1780.75
Bei Strings mit vielen Einträgen (>10K) wird das sehr spürbar. Gibt es da eine schnellere Alternative oder muss ich mich irgendwie über Speicheroperatoren durch den String hangeln? Letzteres würde ich lieber meiden, da ich wahrscheinlich ASCI/Unicode-Unterscheidungen machen müsste.
viele Grüße,
SBond
Re: StringField()-Alternative
Verfasst: 10.07.2017 11:58
von Kiffi
das hier ist ein wenig schneller:
Code: Alles auswählen
Define myString.s = ""
Define entries = 16000
For x = 1 To entries
myString + Str(x) + #CRLF$
Next
Define CrLf.s = #CRLF$
Define SelLine.s
Define Value.s
T1 = ElapsedMilliseconds()
! $.each( v_mystring.split(v_crlf) , function( index, v_value ) {
SelLine = Value
! });
T2 = ElapsedMilliseconds()
Debug "Dauer: " + Str(T2-T1) + " ms"
Debug "Einträge: " + Str(entries)
Debug "Einträge pro Sek: " + StrD(entries/((T2-T1)/1000),2)
Grüße ... Peter
Re: StringField()-Alternative
Verfasst: 10.07.2017 12:02
von NicTheQuick
Das hat natürlich eine quadratische Laufzeit, weil jedes mal durch den kompletten String gelaufen wird um dann genau den Eintrag mit dem richtigen Index heraus zu nehmen.
Wenn man sowieso alle Einträge aus dem String braucht, splittet man ihn lieber direkt und packt ihn in einer Array oder eine LinkedList.
Ich habe da mal schnell etwas zusammen gebastelt, das alle Einträge eines so geteilten Strings in ein Array entpackt. Die Array-Größe wird dabei automatisch in O(1) angepasst.
Code: Alles auswählen
EnableExplicit
Procedure explode(in.s, Array out.s(1), sep.s = ",")
Protected *i.Character = @in, *s.Character = @sep, *start = *i
Protected index.i = 0, element.s
Repeat
If *i\c = *s\c Or *i\c = 0
*s + SizeOf(Character)
If *s\c = 0 Or *i\c = 0
element = PeekS(*start, ((*i - *start) - (*s - @sep)) / SizeOf(Character) + 1)
If ArraySize(out()) < index
ReDim out((ArraySize(out()) + 1) * 2 - 1)
EndIf
out(index) = element
If *i\c = 0
Break
EndIf
index + 1
*start = *i + SizeOf(Character)
*s = @sep
EndIf
EndIf
*i + SizeOf(Character)
ForEver
ReDim out(index)
ProcedureReturn index + 1
EndProcedure
Dim out.s(0)
Define found.i
found = explode(", hi, wie, geht,, es dir?, so", out(), ", ")
Debug "" + found + " Element gefunden."
Define i.i
For i = 0 To ArraySize(out())
Debug "out(" + i + ") = '" + out(i) + "'"
Next
Edit: Ach Mist, das war ja schon wieder für Spiderbasic.
Re: StringField()-Alternative
Verfasst: 10.07.2017 12:55
von SBond
Kiffi hat geschrieben:das hier ist ein wenig schneller
naja "ein wenig"?! Das geht ab wie ein Zäpfchen
Ich sollte wohl mal ein Crash-Kurs in JS machen
vielen Dank euch beiden
viele Grüße,
Martin
Re: StringField()-Alternative
Verfasst: 10.07.2017 13:24
von Kiffi
SBond hat geschrieben:Das geht ab wie ein Zäpfchen
es geht noch schneller (mit forEach):
Code: Alles auswählen
myString.s = ""
entries.i = 1000000
For x = 1 To entries
myString + Str(x) + #CRLF$
Next
Define CrLf.s = #CRLF$
Define SelLine.s
Define Value.s
T1 = ElapsedMilliseconds()
! $.each( v_mystring.split(v_crlf) , function( index, v_value ) {
SelLine = Value
! });
T2 = ElapsedMilliseconds()
Debug "$.each()"
Debug "Dauer: " + Str(T2-T1) + " ms"
Debug "Einträge: " + Str(entries)
Debug "Einträge pro Sek: " + StrD(entries/((T2-T1)/1000),2)
Debug "------------------"
T1 = ElapsedMilliseconds()
! v_mystring.split(v_crlf).forEach( function( v_value, index ) {
SelLine = Value
! });
T2 = ElapsedMilliseconds()
Debug "().forEach"
Debug "Dauer: " + Str(T2-T1) + " ms"
Debug "Einträge: " + Str(entries)
Debug "Einträge pro Sek: " + StrD(entries/((T2-T1)/1000),2)
Debug "------------------"
Grüße ... Peter
Re: StringField()-Alternative
Verfasst: 10.07.2017 14:35
von SBond
oh ha
Ja da bin ich wunschlos glücklich
Tja dann ist heute abend wohl Kalsarikännit angesagt
viele Grüße,
Martin