Array oder String+Stringsplit schneller?

  • Hi,

    wenn du viel Wert auf Performance legst würde ich die ganz normale Array-Variante vorziehen.
    _ArrayAdd(...) braucht (wahrscheinlich) aufgrund des ständigen ReDims extrem lange, StringSplit(...) muss den Datensatz zum Schluss nochmals abarbeiten, deshalb ist auch diese Variante (etwas) langsamer als die Array Version.
    Hier mal ein Testskript, _E3() ist wie schon geschrieben am schnellsten:

    Timer-Test
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $iPasses = 10000

    [/autoit] [autoit][/autoit] [autoit]

    _E1()
    _E2()
    _E3() ; => Am schnellsten!

    [/autoit] [autoit][/autoit] [autoit]

    Func _E1()
    Local $hTimer, $sString, $aArray
    $hTimer = TimerInit()
    For $i = 0 To $iPasses
    $sString &= $i & '|'
    Next
    $aArray = StringSplit($sString, '|', 2)
    MsgBox(64, 'Finished E1 (StringSplit)', 'Time (ms): ' & Round(TimerDiff($hTimer), 2))
    ;_ArrayDisplay($aArray)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _E2()
    Local $hTimer, $aArray[1]
    $hTimer = TimerInit()
    For $i = 1 To $iPasses
    _ArrayAdd($aArray, $i)
    Next
    MsgBox(64, 'Finished E2 (_ArrayAdd)', 'Time (ms): ' & Round(TimerDiff($hTimer), 2))
    ;_ArrayDisplay($aArray)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _E3()
    Local $hTimer, $aArray[$iPasses]
    $hTimer = TimerInit()
    For $i = 0 To $iPasses-1
    $aArray[$i] = $i
    Next
    MsgBox(64, 'Finished E3 (Array)', 'Time (ms): ' & Round(TimerDiff($hTimer), 2))
    ;_ArrayDisplay($aArray)
    EndFunc

    [/autoit]

    2 Mal editiert, zuletzt von John8 (30. April 2014 um 12:44)

    • Offizieller Beitrag

    Da die Arraygröße erst am Schluss bekannt ist, ist stringsplit wohl die beste Lösung.


    Nicht unbedingt. Du kannst doch sicher abschätzen, ob es 100.000 oder 1.000.000 Einträge werden. Erstelle ein Array am Beginn, das auf jeden Fall größer ist als die zu erwartende Anzahl an Einträgen. Den Zähler für die Anzahl Elemente erhöhst du bei jedem neuen Element und verwendest ihn dann als Index für den Eintrag im Array (Achtung: Index beginnt bei 0). Nach dem letzten Element-Eintrag schneidest du mit ReDim die überzähligen Arrayelemente ab. Du kannst auch den Zähler an Position [0] im Array führen, wenn die Anzahl der Elemente im weiteren von Bedeutung ist (erspart dir ein UBound ;)).

    Spoiler anzeigen
    [autoit]

    Global $array[100000] = [0] ; Zähler an [0] führen

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To $iPasses
    $array[$array[0]] = $i ; Eintrag an aktueller Zählerposition
    $array[0] += 1 ; Zähler um eins erhöhen
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ReDim $array[$array[0]]

    [/autoit]
  • In diesem Fall wird man aber wahrscheinlich gerade langsamer sein, da ja jedesmal noch $Array[0] inkrementiert wird:

    Speedvergleich
    [autoit]

    Global Const $N = 10000

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $iT = TimerInit()
    Global $a_R[1e6]
    For $i = 1 To $N
    $a_R[0] += 1
    $a_R[$a_R[0]] = $i
    Next
    ReDim $a_R[$N+1]
    $iT = TimerDiff($iT)
    ConsoleWrite(StringFormat("%15s:\t%6.2f ms\n", "Array + Redim ", $iT))

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $iT = TimerInit()
    Global $s_S = ""
    For $i = 1 To $N
    $s_S &= $i & '|'
    Next
    Global $a_R = StringSplit(StringTrimRight($s_S, 1), "|")
    $iT = TimerDiff($iT)
    ConsoleWrite(StringFormat("%15s:\t%6.2f ms\n", "String & ", $iT))

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $iT = TimerInit()
    Global $a_R[$N+1] = [$N]
    For $i = 1 To $N
    $a_R[$i] = $i
    Next
    $iT = TimerDiff($iT)
    ConsoleWrite(StringFormat("%15s:\t%6.2f ms\n", "Array ", $iT))

    [/autoit]


    Mal abgesehen davon das nicht nur die "Schnelligkeit" ein optimales Programm ausmacht sondern auch der Speicherverbrauch.
    Und einfach so ein Array mit Mondgröße zu initialisieren spricht dem ziemlich entgegen.

    FKFK:
    Stringsplit fetzt - nimm es.