1D Array in 2D Array splitten

  • Hallo,

    ich benutzte diese Funktion zum Arraysplit.

    Allerdings benötigt sie sehr viel Zeit. Für 3000 Zeilen (aus einem 1D Array werden ~55 Reihen 2D Array erstellt) ca. 2,5 Minuten...

    Kann man den Split noch beschleunigen?

    @@ Debug(618) : _StringSplit2D Start!: / Zeit:21:33:08
    @@ Debug(644) : _StringSplit2D END!: / Zeit:21:35:29

    Danke und Gruß,

    Horphi

  • Ich nehme mal stark an, dass dein größter Performanceverlust die dauernden ReDims sind.
    Guck dir z.B. mal @AspirinJunkies DynArray UDF an, dort erstellt er Arrays die doppelt / dreifach so groß sind wie benötigt und kennzeichnet im Array wie befüllt es ist.
    So kannst du dir die etlichen ReDims sparen und statt beispielsweise 100 ReDims nur eins vornehmen.

  • Hallo @horphi,
    Ohne von der DynArray UDF abraten zu wollen, will ich nur folgendes zu ReDim schreiben:
    Genau wie @alpines es breits geschrieben hat, vermute auch ich hier das Problem.

    Beispielhaft für eine deiner Schleifen:
    Statt $aRet[1][1] zu deklarieren, würde ich es direkt mit maximalen Größe erstellen (UBound($aTmp).
    So muss das Array nicht mehrfach vergrößert werden (Langwieriger Prozess, mit kopieren des vorhandenen Arrays).
    Wenn unter Umständen das Zielarray am Ende nicht so groß sein soll, wie die Anzahl der Schleifendurchläufe, dann empfiehlt sich eine Zähler-Variable.
    Hier ein Beispiel:

    (Auch habe ich schon Arrays in Größe deklariert, die sicher nicht erreicht wurde. Etwa $aArray[10000][200] und ohne Ubound mit einer Zählervariable (oder zwei, falls zweidimensional und notwendig ) das Array nach der Schleife mit ReDim angepasst.)

    Grüße autoiter

  • Hallo @horphi !
    ReDim wird nur benötigt, wenn Du die Größe eines bestehenden Arrays verändern willst (dieser Prozess ist recht zeitintensiv).
    Ist Dir die Größe des Arrays bereits bekannt, dann kannst Du es auch gleich 'richtig' dimensionieren.

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • Eine weitere Möglichkeit wäre erst einmal mit einem Array-In-Array zu arbeiten statt direkt mit einem 2D-Array und erst ganz am Ende daraus das 2D-Array zu erzeugen.
    Dann wird deine Funktion ziemlich trivial:


    In einer Funktion kombiniert würde dann so aussehen:

    Ein ReDim würde nur erfolgen wenn eine Zeile mehr Elemente hat als bisherige.
    Im konkreten Beispiel also nur ein einziges mal - das ist verkraftbar.

    • Offizieller Beitrag

    Ein ReDim würde nur erfolgen wenn eine Zeile mehr Elemente hat als bisherige.
    Im konkreten Beispiel also nur ein einziges mal - das ist verkraftbar.

    Stimmt! So benötigt man nur ein ReDim.
    Es geht aber auch ganz ohne ReDim, indem man ein zusätzliches StringSplit einfügt:


    Das zusätzliche StringSplit ist auch etwas schneller als das ReDim. Wobei sich das erst bei mehreren Durchläufen bemerkbar macht:

  • Das wäre tastächlich die favorisierte Variante wenn bekannt ist dass alle Zeilen die selbe Anzahl an Delimitern haben.
    Ich bin halt auch davon ausgegangen, dass einige Zeilen weniger enthalten können als andere.
    Wenn z.B. die erste Zeile nur 5 Elemente hat und alle anderen 7.

    Statt dem StringSplit für die Anzahl der Delimiter für die zweite Dimension wäre wahrscheinlich ein StringReplace + @extended die schnellere Variante.

    • Offizieller Beitrag

    Ich bin halt auch davon ausgegangen, dass einige Zeilen weniger enthalten können als andere.
    Wenn z.B. die erste Zeile nur 5 Elemente hat und alle anderen 7.

    Ah, ok! Wenn die Daten in der zweiten Dimension eine unterschiedliche Anzahl an Elementen aufweisen, dann lieber so, wie von Dir vorgeschlagen.

    Und: ja, StringReplace und @extended ist noch etwas schneller als StringSplit:


    Und es ist auch gar nicht das eine ReDim, was zu der kürzeren Laufzeit führt, sondern das fehlen der If-Anweisung innerhalb der For...Next-Schleife.

  • Na dann gehen wir doch mal ans Finetuning:

    • Beim StringSplit auch den ENTIRESPLIT-Parameter setzen (also =3) - sollte in dem Fall ca. Faktor 3 schneller sein.
    • Beim StringReplace den CaseSense-Parameter auf 1 setzen - wird hier nur einmal aufgerufen daher fast egal (könnte dort aber ca. Faktor 20 ausmachen)
    • Als Ersatzstring bei StringReplace einen String der selben Länge nehmen wie der Suchstring
    • Die Variable $tmp kann weg
    • Wer sieht noch was?
    • Offizieller Beitrag

    Mit allen Optimierungen (das mit ENTIRESPLIT hat mich überrascht) bei beiden Funktionen, sind sie nahezu gleichauf (120ms weniger bei der New-Variante).
    Dafür ist Deine Funktion universeller (wegen automatischer Anpassung der 2. Dimension):

    Ich denke, dass ich mich geschlagen gebe und Deine Funktion als Gewinner darstelle. :thumbup:

  • Sach mal, da bin ich ein paar Stunden auf der Fähre und ihr fangt an hier sowas zu zaubern... WOW. :)

    Vielen Dank. :thumbup:

    Die probier ich gleich mal aus.

    Viele Grüße,

    horphi