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. :lol:

Re: StringField()-Alternative

Verfasst: 10.07.2017 12:55
von SBond
Kiffi hat geschrieben:das hier ist ein wenig schneller
:shock: naja "ein wenig"?! Das geht ab wie ein Zäpfchen :mrgreen:
Ich sollte wohl mal ein Crash-Kurs in JS machen :lol:

vielen Dank euch beiden :mrgreen:

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 :mrgreen:

viele Grüße,
Martin