Alternativen zum Array

  • In AutoIt werden fast außschließlich Arrays (Felder) als Datenstruktur eingesetzt.
    Arrays sind aber nicht immer die beste Wahl.
    Im Prinzip stellt ein Array einen Speicherbereich dar in dem alle Werte hintereinander stehen.
    Das führt dazu das man die einzelnen Werte mit einem Index ansprechen kann.
    Allerdings hat dies auch einen entscheidenden Nachteil:
    Arrays sind absolut undynamisch.
    Wenn man ein Element hinzufügen möchte, muss das komplette Array dann in einen Speicherbereich kopiert werden der dessen Größe aufnehmen kann.
    Ebenso verhält es sich beim Löschen eines Elementes - mindestens die nachfolgenden Elemente müssten alle um eine Position verrückt werden.
    Das führt dazu das bei solchen Aktionen Arrays enorm uneffizient sind und man nach Alternativen Ausschau halten sollte welche dieses Problem nicht haben und wenn es geht noch andere Vorteile bieten.

    Die wichtigsten dieser Alternativen möchte ich hier nun vorstellen und zeigen wie man sie in AutoIt verwenden kann:

    Die Liste

    Bei einer Liste stehen die einzelnen Elemente nicht hintereinander im Speicher sondern alle verteilt.
    Damit die Liste zu einer Einheit wird enthalten die einzelnen Elemente zusätzlich zu ihrem Wert noch eine Information darüber wo sich das nächste Element im Speicher befindet (Pointer).
    Das führt dazu das man ohne viel Aufwand Elemente löschen oder hinzufügen kann da einfach nur ein Wert erstellt oder gelöscht werden muss und ein entsprechender Verweis beim vorherigen Element geändert werden muss.
    Eine Liste ist in diesen Fällen enorm schneller als ein Array.

    Prinzipiell sind Listen aber nicht indiziert wie z.B. Arrays - möchte man auf die Elemente zugreifen müsste man theoretisch immer die Liste vom Anfang durchlaufen.
    In der Praxis gibt es aber ein paar Tricks wie man dies umgehen kann.

    Verwendung in AutoIt:

    System.Collections.ArrayList
    [autoit]

    #include <Array.au3>

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

    ;----------------------------------------------------------------------
    ;------------------------Array-List------------------------------------
    ;----------------------------------------------------------------------
    ; http://msdn.microsoft.com/de-de/library/….arraylist.aspx

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

    ;////Array-List Erstellen///////////
    $AList = ObjCreate("System.Collections.ArrayList")

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

    ;////Einträge hinzufügen///////////
    $AList.add ("Test1")
    $AList.add ("Test6")
    $AList.add ("Test4")
    $AList.add ("Test2")
    $AList.add ("Test3")
    $AList.add ("Test5")

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

    ;////ArrayList sortieren///////////
    $AList.sort

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

    ;////alle Elemente durchgehen///////////
    For $element In $AList
    ConsoleWrite($element & @CRLF)
    Next

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

    ;////Element löschen///////////
    $AList.Remove("Test2") ;Löscht das angegebene Element (soweit vorhanden)

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

    ;////löscht Eintrag an gegebenen Index///////////
    $AList.RemoveAt (3) ;Entfernt das Element an der 4. Position

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

    ;////gibt Eintrag an gegebenen Index zurück///////////
    $Item = $AList.Item(2) ;gibt den Index des Items an der 3. Stelle zurück

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

    ;////Eintrag an bestimmter Stelle einfügen///////////////
    $AList.Insert (2, "Eingefügt!") ;fügt Wert an 3. Position ein.

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

    ;////Anzahl der Elemente bestimmen///////////
    $Count = $AList.Count

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

    ;////Überprüft ob ein Element vorhanden ist///////////
    If $AList.Contains ("Test200") Then MsgBox(0, "", "Element vorhanden!") ;hier im Beispiel ist Element nicht vorhanden

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

    ;////Listen zusammenfügen///////////
    $queue = ObjCreate("System.Collections.Queue")
    $queue.Enqueue ("QueueWert1")
    $queue.Enqueue ("QueueWert2")
    $queue.Enqueue ("QueueWert3")
    $queue.Enqueue ("QueueWert4")
    $AList.AddRange ($queue)

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

    ;////Umwandlung in Array///////////
    $Array = $AList.ToArray ;kopiert Werte in ein Array (Liste ist immer noch vorhanden)
    _ArrayDisplay($Array, "Test")

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

    ;////Löscht Liste///////////
    $AList.Clear

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

    ;////Index eines Elementes bestimmen///////////
    $Index = _ArrayList_GetIndexOf($AList, "Test1")

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

    Func _ArrayList_GetIndexOf(ByRef $ArrayList, $element)
    Local $counter = 0

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

    If Not IsObj($ArrayList) Then
    SetError(1)
    Return 0
    EndIf

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

    For $elem In $AList
    If $elem = $element Then Return $counter
    $counter += 1
    Next

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

    SetError(2)
    Return 0
    EndFunc

    [/autoit]

    Natürlich können die Elemente dieser Strukturen auch Arrays sein - das hat dann einen ähnlichen Effekt wie ein 2-Dim-Array.
    Hier mal ein Beispiel dazu:

    Spoiler anzeigen
    [autoit]

    $TestList = ObjCreate("System.Collections.ArrayList")

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

    For $i = 0 To 25
    Dim $TestArray[4] = [$i, 2 * $i, 3 * $i, 4 * $i]
    $TestList.add ($TestArray)
    Next

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

    For $element In $TestList
    ConsoleWrite(StringFormat("%2d",$element[0]) & ' ' & StringFormat("%2d",$element[1]) & ' ' & StringFormat("%2d",$element[2]) & ' ' & StringFormat("%2d",$element[3]) & @CRLF)
    Next

    [/autoit]

    Die Warteschlange (Queue)

    Eine Queue ist im Prinzip eine Art Liste.
    Allerdings hat man hierbei immer nur Zugriff auf ein Element - nämlich das was als erstes hinzugefügt wurde.
    Eine Queue arbeitet nämlich im FirstIn-FirstOut-Prinzip.
    Als praktisches Beispiel gilt der Namensgeber.
    Alle Elemente werden hinzugefügt.
    Dann arbeitet man der Reihe nach die Elemente ab in der Reihenfolge wie sie hinzugefügt wurden.
    Holt man das erste Element heraus steht nun das vormals 2. als nächstes bereit usw.
    Dennoch kann man munter weiter Elemente hinzufügen.


    Verwendung in AutoIt:

    System.Collections.Queue
    [autoit]

    #include <Array.au3>

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

    ;----------------------------------------------------------------------
    ;------------------------Queue-----------------------------------------
    ;----------------------------------------------------------------------
    ; http://msdn.microsoft.com/de-de/library/…ions.queue.aspx

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

    ;////Queue Erstellen///////////
    $queue = ObjCreate("System.Collections.Queue")

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

    ;////Eintrag an das Ende der Warteschlange hinzufügen///////////
    $queue.Enqueue ("Erster Eintrag")
    $queue.Enqueue ("Zweiter Eintrag")
    $queue.Enqueue ("Dritter Eintrag")
    $queue.Enqueue ("Vierter Eintrag")

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

    ;////Überprüft ob ein Element vorhanden ist///////////
    If $queue.Contains ("Fünfter Eintrag") Then MsgBox(0, "", "is drin!")

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

    ;////Erstes Element anzeigen (ohne löschen)///////////
    ConsoleWrite( $queue.Peek & @CRLF )

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

    ;////Anzahl der Elemente bestimmen///////////
    $Count = $queue.Count

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

    ;////Erstes Element herausholen///////////
    $firstelement = $queue.Dequeue

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

    ;////Umwandlung in Array///////////
    $Array = $queue.ToArray
    _ArrayDisplay($Array, "Test")

    [/autoit]

    Der Stapelspeicher (Stack)

    Ein Stack ist im Prinzip eine invertierte Queue denn er arbeitet im LastIn-FirstOut-Prinzip.
    Im Gegensatz zur Queue kann man hier also nur das letzte Element was man hinzugefügt hatte herausholen.

    Verwendung in AutoIt:

    System.Collections.Stack
    [autoit]

    #include <Array.au3>

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

    ;----------------------------------------------------------------------
    ;------------------------Stack-----------------------------------------
    ;----------------------------------------------------------------------
    ; http://msdn.microsoft.com/de-de/library/…ions.stack.aspx

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

    ;////Stack Erstellen///////////
    $Stack = ObjCreate("System.Collections.Stack")

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

    ;////Eintrag an den Stack anfügen///////////
    $Stack.Push ("Erster Eintrag")
    $Stack.Push ("Zweiter Eintrag")
    $Stack.Push ("Dritter Eintrag")
    $Stack.Push ("Vierter Eintrag")

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

    ;////Oberstes Element herausholen///////////
    $firstelement = $Stack.Pop

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

    ;////Erstes Element anzeigen (ohne löschen)///////////
    ConsoleWrite( $Stack.Peek & @CRLF)

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

    ;////Anzahl der Elemente bestimmen///////////
    $Count = $Stack.Count

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

    ;////Überprüft ob ein Element vorhanden ist///////////
    If $Stack.Contains ("Fünfter Eintrag") Then MsgBox(0, "", "Element vorhanden")

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

    ;////Umwandlung in Array///////////
    $Array = $Stack.ToArray
    _ArrayDisplay($Array, "Test")

    [/autoit]

    Die Hash-Tabelle

    Eine HashTable ist eine indizierte Datenstruktur.
    Das heißt einem Index wird ein Wert zugeordnet.
    Wenn man den Namen des Index kennt kann man damit sehr schnell auf seinen entsprechenden Wert zugreifen.

    Eine bessere Vorstellung davon sollte man anhand der Beispielimplementierung in AutoIt erhalten:

    System.Collections.Hashtable
    [autoit]

    ;----------------------------------------------------------------------
    ;------------------------Hash-Table------------------------------------
    ;----------------------------------------------------------------------
    ; http://msdn.microsoft.com/de-de/library/….hashtable.aspx

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

    ;////Hash-Table Erstellen///////////
    $hash = ObjCreate("System.Collections.Hashtable")

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

    ;////Einträge hinzufügen///////////
    $hash.add ("Berlin", 3395189)
    $hash.add ("Hamburg", 1743627)
    $hash.add ("München", 1259677)
    $hash.add ("Köln", 983347)
    $hash.add ("Dresden", 504795)
    ;Beispiel hier: Einwohnerzahl wird der jeweiligen Stadt zugeordnet.

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

    ;////Anzahl der Elemente bestimmen///////////
    $Count = $hash.Count

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

    ;////Überprüft ob ein Element vorhanden ist///////////
    If $hash.Contains ("Bonn") Then MsgBox(0, "", "Bonn ist eingetragen") ;Bonn ist im Bsp. nicht enthalten

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

    ;////Löscht ein Element aus der Hash-Table///////////
    $hash.remove ("München")

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

    ;////Elemente aufrufen///////////
    ConsoleWrite("Einwohner(Berlin): " & $hash("Berlin") & @CRLF)
    ConsoleWrite("Einwohner(Dresden): " & $hash("Dresden") & @CRLF)

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

    ;////Leert die Hash-Table///////////
    $hash.Clear

    [/autoit]


    Das Dictionary

    Das Dictionary ist wie die Hash-Tabelle ein assoziatives Array:

    Scripting.Dictionary
    [autoit]

    ;//// Dictionary Erstellen ///////////
    ; http://msdn.microsoft.com/en-us/library/…4(v=vs.84).aspx
    $oDict = ObjCreate("Scripting.Dictionary")

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

    ;//// Einträge hinzufügen ///////////
    $oDict.add ("Berlin", 3395189)
    $oDict.add ("Hamburg", 1743627)
    ; Alternativ (keine Fehler falls schon existiert und auch Werte damit veränderbar):
    $oDict("München") = 1259677
    $oDict("Köln") = 983347
    $oDict("Dresden") = 529781

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

    ;//// Anzahl der Elemente bestimmen ///////////
    MsgBox(0,"Anzahl Elemente in Dictionary", $oDict.Count)

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

    ;//// Überprüft ob ein Element vorhanden ist ///////////
    If $oDict.Exists ("Bonn") Then MsgBox(0, "", "Bonn ist eingetragen") ;Bonn ist im Bsp. nicht enthalten

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

    ;//// Löscht ein Element aus dem Dictionary ///////////
    $oDict.remove ("München")

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

    ;//// Elemente aufrufen ///////////
    ConsoleWrite("Einwohner(Berlin): " & $oDict("Berlin") & @CRLF)
    ConsoleWrite("Einwohner(Dresden): " & $oDict("Dresden") & @CRLF & @CRLF)

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

    ;//// alle Schlüssel durchgehen ///////////
    For $k in $oDict.Keys
    ConsoleWrite("Einwohner(" & $k & "): " & $oDict($k) & @CRLF)
    Next
    ; Alle Werte statt Schlüssel erreicht man mit $oDict.Items

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

    ;//// Leert das Dictionary ///////////
    $oDict.RemoveAll

    [/autoit]


    Dictionary und Hash-Tabelle unterscheiden sich lediglich hinsichtlich der internen Implementierung.
    Das führt dazu dass ein Dictionary bei einer kleinen Anzahl an Elementen performanter beim Hinzufügen von Elementen ist als die Hash-Tabelle während es sich bei einer großen Anzahl an Elementen andersherum verhält.
    Dies dauert bei einem Dictionary immer länger je mehr Elemente in der Struktur stehen. Bei der Hash-Table bleibt der Zeitaufwand dafür immer der selbe.
    Bei mir liegt diese Grenze grob bei etwa 400.000 Elementen.
    Will man selbst ermitteln ab wann sich eines von beiden eher lohnt kann man z.B. folgendes Skript verwenden ($N anpasen):

    Speedvergleich Dictionary-Hashtable
    [autoit]

    Global $oDic = ObjCreate("Scripting.Dictionary")
    Global $oHash = ObjCreate("System.Collections.Hashtable")

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

    Global Const $N = 1e6

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

    $iT = TimerInit()
    For $i = 1 To $N
    $oDic.add($i, "Teststring")
    Next
    $iT = TimerDiff($iT)
    ConsoleWrite(StringFormat("Dictionary:\t%7.1f ms\n", $it))

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

    $iT = TimerInit()
    For $i = 1 To $N
    $oHash.add($i, "Teststring")
    Next
    $iT = TimerDiff($iT)
    ConsoleWrite(StringFormat("Hash-Table:\t%7.1f ms\n", $it))

    [/autoit]

    Die Sorted-List
    Die Sorted-List ist wie die Hash-Table und das Dictionary ein assoziatives Array (Schlüssel-Wert-Paare).
    Im Unterschied zu diesen stehen die Elemente immer in einer, nach dem Schlüssel, sortierten Reihenfolge.

    System.Collections.SortedList
    [autoit]


    ;----------------------------------------------------------------------
    ;------------------------Sorted-List------------------------------------
    ;----------------------------------------------------------------------
    ; http://msdn.microsoft.com/de-de/library/…sortedlist.aspx

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

    ;//// Sorted-List erstellen ///////////
    $SList = ObjCreate("System.Collections.SortedList")

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

    ;//// Elemente hinzufügen ///////////
    $SList.add("Berlin", 3395189)
    $SList.add("Hamburg", 1743627)
    ; Alternativ (keine Fehler falls schon existiert und auch Werte damit veränderbar):
    $SList("München") = 1259677
    $SList("Köln") = 983347
    $SList("Dresden") = 529781
    $SList("Stuttgart") = 606.588
    $SList("Dortmund") = 580.444

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

    ;//// Test ob Schlüssel oder Wert existiert ///////////
    If $SList.ContainsKey("Bonn") Then MsgBox(0, "", "Bonn ist eingetragen")
    If $SList.ContainsValue(100000) Then MsgBox(0, "", "Eine Stadt mit 100.000 Einwohnern ist eingetragen")

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

    ;//// Elemente anhand Schlüssel oder Index löschen ///////////
    $SList.Remove("München") ; Eintrag "München" wird gelöscht
    $SList.RemoveAt(3) ; der 2. Eintrag (Hamburg) wird gelöscht

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

    ;//// Elemente anhand Schlüssel oder Index suchen ///////////
    ConsoleWrite("Index von Köln: " & $SList.IndexOfKey("Köln") & @CRLF)
    ConsoleWrite("Index der Stadt mit 529.781 Einwohnern: " & $SList.IndexOfValue(529781) & @CRLF & @CRLF)

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

    ;//// Alle Elemente durchlaufen ///////////
    For $i = 0 To $SList.Count - 1
    ConsoleWrite($SList.GetKey($i) & @TAB & $SList.Getbyindex($i) & @CRLF)
    Next

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

    ;//// Sorted-List leeren ///////////
    $SList.Clear

    [/autoit]

    Nun ich hoffe die hier vorgestellten Alternativen regen den ein oder anderen dazu an wenigstens mal zu schauen was damit geht und gegebenfalls das nächste mal einfach mal auf ein Array zu verzichten... ;)
    Zu einer effektiven Programmgestaltung können diese Datenstrukturen eine Menge beitragen.

    Und um die Sache zum Ausprobieren noch ein bisschen schmackhafter zu machen habe ich hier noch eine Funktion erstellt welche ein 1-Dim-Array direkt in eine Liste, Queue oder Stack umwandelt:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    Global $Arr[5] = [1, 2, 3, 4, 5]

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

    $Queue = _ArrayToList($Arr, "Queue", 0, UBound($Arr) - 1, 1)

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

    If Not @error Then
    $Temp = $Queue.ToArray
    _ArrayDisplay($Temp)
    EndIf

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

    ;=================================================================================================
    ;
    ; Function Name: _ArrayToList()
    ; Description: Konvertiert ein 1-dimensionales Array in eine Liste, Queue oder Stack
    ;
    ; Parameter(s): $Array - Das zu konvertierende Array
    ; [Typ] - gewünschter Datenstrukturtyp:
    ; "List" = ArrayList (Default)
    ; "Queue" = Warteschlange
    ; "Stack" = Stapelspeicher
    ; [$von] - Start array index (Default = 0)
    ; [$bis] - End array index (Default = Ubound - 1)
    ; [DeleteArray] - löscht das umzuwandelnde Array nach Abarbeitung (Default = 0)
    ;
    ; Requirement(s): None.
    ; Return Value(s): bei Erfolg - Die gewünschte Datenstruktur
    ; Bei Fehler - 0
    ; @Error=1 - kein korrektes Array als Parameter angegeben
    ; @Error=2 - Bereichsfehler eines angegebenen Index
    ; @Error=3 - Falsche Angabe für den $Typ-Parameter
    ;
    ; Author(s): [email='AspirinJunkie@german-nlite.de'][/email]
    ;
    ; Note(s): Durch Vertauschen des $von mit dem $bis Parameter kann die
    ; Reihenfolge der Elemente vertauscht werden.
    ;
    ;=================================================================================================

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

    Func _ArrayToList(ByRef $Array, $Type = "List", $von = 0, $bis = Default, $DeleteArray = 0)
    Local $i, $Liste, $Step = 1

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

    If Not IsArray($Array) Then
    SetError(1)
    Return 0
    EndIf

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

    If $bis = Default Then $bis = UBound($Array) - 1

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

    If $bis > UBound($Array) - 1 Or $von > UBound($Array) - 1 Or 0 > $von Or 0 > $bis Then
    SetError(2)
    Return 0
    EndIf

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

    If $von > $bis Then $Step = -1

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

    Switch $Type

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

    Case "List"
    $Liste = ObjCreate("System.Collections.ArrayList")
    For $i = $von To $bis Step $Step
    $Liste.Add ($Array[$i])
    Next

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

    Case "Queue"
    $Liste = ObjCreate("System.Collections.Queue")
    For $i = $von To $bis Step $Step
    $Liste.Enqueue ($Array[$i])
    Next

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

    Case "Stack"
    $Liste = ObjCreate("System.Collections.Stack")
    For $i = $von To $bis Step $Step
    $Liste.Push ($Array[$i])
    Next

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

    Case Else
    SetError(3)
    Return 0

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

    EndSwitch

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

    If $DeleteArray Then $Array = 0

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

    Return $Liste
    EndFunc ;==>_ArrayToList
    ;=================================================================================================

    [/autoit]

    P.S.: Hoffe mal BugFix liest das hier nicht - ich will nicht wissen was los ist wenn er sieht das ich öffentlich das Array diffamiere.... [Blockierte Grafik: http://forum.team-ingame.de/images/smilies/sofa.gif]

    2 Mal editiert, zuletzt von AspirinJunkie (4. Oktober 2012 um 10:04)

  • Hallo.

    erst einmal finde ich diesen Beitrag gerade für Anfänger/innen sehr sehr gut.

    Da hier die akute BugFix-Gefahr besteht (SPASS), habe ich mir den Beitrag und die Scripte dazu schnell mal gesichert. ;)

    Also, jetzt warte ich mal auf ein Conter von BugFix. Vielleicht erklärt er Arrys soooooooo gut, das auch Anfänger/innen damit zurecht kommen.

    Wichtig sind Beispiele, denn ohne versteht man gerade am Anfang nicht viel. Das ist nicht böse gemeint, aber für User/innen, die sich immer wiedder gerne mit neuen Sachen beschäftigen und dann Arrys sich vornehmen, sind Beispiele und evtl. verständliche Zeichnungen einfach besser. Gibt Studien, das Menschen durch Beispiele und Grafiken zu Beispielen um einiges besser das Eigentliche verstehen.

    In diesem Sinn mal LG sendet.

    Lina

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

    • Offizieller Beitrag
    Zitat

    P.S.: Hoffe mal BugFix liest das hier nicht - ich will nicht wissen was los ist wenn er sieht das ich öffentlich das Array diffamiere.... [Blockierte Grafik: http://forum.team-ingame.de/images/smilies/sofa.gif]

    [Blockierte Grafik: http://home.arcor.de/bugfix/tux_hard.gif] Array-Diffamierung? Ich bin erschüttert. Aber mein Freund aus der Linux-Welt eilt schon zu Hilfe! :D

    Aber mal ernsthaft, auch wenn ich Arrays liebe ( mehr als meine Frau ???, ..hmm.... überleg ...lieber-still-schweig ;) ), so bin ich doch immer interessiert an Lösungen, die ein Programm effektiver machen können.
    Also AspirinJunkie: Ich werde keinen Bann über dich legen. ;)
    Werde es auf jeden Fall ausprobieren.

  • AspirinJunkie
    Jetzt krieg ich Kopfschmerzen. Welche Vorteile bringen mir Deine Anregungen? Spare ich Arbeitsspeicher? Ist AutoIt schneller? In welchen Situationen sind diese Beispiele Arrays vorzuziehen?

    Bin nichts so sehr damit vertraut, wie effizient AutoIt oder Arrays sind. Hast Du noch einige weitere Details dazu?

    • Offizieller Beitrag

    Mit diesen Methoden sparst du
    a) Speicherplatz, da nicht der Inhalt eines gesamten Arrays zwischengeparkt werden muß
    und
    b) verringert sich die Zugriffszeit auf Elemente.

    Bei Arrays mit 10 oder auch 100 Elementen wird der Unterschied noch nicht gravierend sein. Aber bei großen Datenmengen sicher.

  • Danke BugFix, ich glaube, ich habe einfach noch nicht so viel mit Arrays am Hut gehabt, um die Vor- und Nachteile in der Praxis nachvollziehen zu können. Da werden die Alternativen deutlich interessanter.

    Einmal editiert, zuletzt von unearth (1. August 2007 um 20:49)

  • Eine Liste hat im Vergleich zu einem Array vor allem dann Vorteile wenn es darum geht öfters Elemente der Datenstruktur hinzuzufügen oder zu entfernen.
    In diesem Fall ist der Geschwindigkeitszuwachs enorm.
    Diesen Vorteil haben alle hier vorgestellten Strukturen gegenüber einen Array.

    Wenn die Datenmenge stabil bleibt ist ein Array die von der Performance her gesehen die wohl etwas bessere Wahl.

    Desweiteren bietet beispielsweise die Hashtabelle Vorteile wenn du einem Index einen Wert zuweist.
    Würde man etwas ähnliches über Arrays bewerkstelligen wollen würde man auf ein 2D-Array ausweichen welches einmal den Namen des Index enthält und als 2. den entsprechenden Wert.
    Hat man nun den Indexnamen und möchte den passenden Wert dazu müsste man erst das gesamte Array danach durchsuchen - hier hat die Hash-Tabelle wiederrum Vorteile - vor allem in der Geschwindigkeit und in der Komplexizität das dafür nötigen Codes.

    Ein Stack oder eine Queue können vor allem den Code deutlich vereinfachen.
    Prinzipiell braucht man bei einem Stack ja fast nur Push und Pop - viel einfacher kann man es gar nicht haben... ;)

    Zusammengefasst:

    Diese Möglichkeiten können(!!!) die Performance drastisch erhöhen, die Speicherauslastung effizienter gestalten und den Code verkürzen und vereinfachen.
    Dies ist aber abhängig von der entsprechenden Verwendung.
    Alle Methoden haben ihre Vor und Nachteile.

  • Da mittlerweile das Interesse an Array-Alternativen gestiegen ist (siehe Dictionary-Object-Thread) hier mal noch 2 Funktionen die einen Blick über den Array-Tellerrand noch ein wenig schmackhafter machen könnten:

    FileListToList und FileReadToList welche prinzipiell ein Pendant zu _FileReadToArray und _FileListToArray darstellen - nur mit dem Unterschied das sie statt einem Array ein Array-List Objekt zurückgeben.
    Viel Spaß damit:

    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ;
    ; Description: Reads the specified file into an array-list object
    ; Syntax: _FileReadToList($File)
    ; Parameter(s): $File - Path and filename of the file to be read
    ; Requirement(s): None
    ; Return Value(s): On Success - Returns 1
    ; On Failure - Returns 0 and sets @error on errors
    ; @Error=1 Failure Creating the ArrayList-Object
    ; @Error=2 Failure Creating the FileSystem-Object
    ; @Error=3 File don´t exists
    ;
    ; Author(s): AspirinJunkie <AspirinJunkie at german-nlite dot de>
    ; Note(s): None
    ;
    ;===============================================================================
    Func _FileReadToList($File)
    Local $FileHandle
    Local $List = ObjCreate("System.Collections.ArrayList")
    If @error Then Return SetError(1, 1, 0)
    Local $FSObj = ObjCreate('Scripting.FileSystemObject')
    If @error Then Return SetError(2, 2, 0)

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

    If Not $FSObj.FileExists($File) Then Return SetError(3, 3, 0)

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

    $FileHandle = $FSObj.OpenTextFile ($File, 1)

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

    Do
    $List.add ($FileHandle.ReadLine ())
    Until $FileHandle.AtEndOfStream ()

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

    $FileHandle.close

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

    Return $List
    EndFunc ;==>_FileReadToList
    ;===============================================================================

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

    ;===============================================================================
    ;
    ; Description: lists all files and folders in a specified path (Similar to using Dir with the /B Switch)
    ; Syntax: _FileListToList($Path, $Filter = "*", $Flag = 0)
    ; Parameter(s): $Path = Path to generate filelist for
    ; $sFilter = The filter to use. Search the Autoit3 manual for the word "WildCards" For details
    ; $iFlag = determines weather to return file or folders or both
    ; $iFlag=0(Default) Return both files and folders
    ; $iFlag=1 Return files Only
    ; $iFlag=2 Return Folders Only
    ;
    ; Requirement(s): None
    ; Return Value(s): On Success - Returns an Array-List Object containing the list of files and folders in the specified path
    ; On Failure - Returns the an empty string "" if no files are found and sets @Error on errors
    ; @Error=1 Failure Creating the ArrayList-Object
    ; @Error=2 Failure Creating the FileSystem-Object
    ; @Error=3 Invalid $Flag
    ; @Error=4 $Path don´t exists
    ;
    ; Author(s): AspirinJunkie <AspirinJunkie at german-nlite dot de>
    ; Note(s): -
    ;===============================================================================
    Func _FileListToList($Path, $Filter = '*', $Flag = 0)
    Local $Folder, $i, $e
    Local $Replaces[8][2] = [['.', '\.' ], ['*', '.*' ], ['?', '.' ], ['+', '\+' ], ['-', '\-' ], ['(', '\(' ], [')', '\)' ], ['[', '\[' ]]
    Local $List = ObjCreate("System.Collections.ArrayList")
    If @error Then Return SetError(1, 1, '')
    Local $FSObj = ObjCreate('Scripting.FileSystemObject')
    If @error Then Return SetError(2, 2, '')

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

    For $i = 0 To 7
    $Filter = StringReplace($Filter, $Replaces[$i][0], $Replaces[$i][1])
    Next

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

    $Filter = '^' & $Filter & '\z'

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

    If Not ($Flag = 0 Or $Flag = 1 Or $Flag = 2) Then Return SetError(3, 3, '')
    If Not $FSObj.FolderExists ($Path) Then Return SetError(4, 4, '')

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

    $Folder = $FSObj.GetFolder ($Path)

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

    If $Flag < 2 Then
    For $e In $Folder.Files
    If StringRegExp($e.Name, $Filter) Then $List.add ($e.Name)
    Next
    EndIf

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

    If Not ($Flag = 1) Then
    For $e In $Folder.SubFolders
    If StringRegExp($e.Name, $Filter) Then $List.add ($e.Name)
    Next
    EndIf

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

    Return $List
    EndFunc ;==>_FileListToList
    ;===============================================================================

    [/autoit]
  • Hi
    der Beitrag ist schon älter, aber ich hoffe das Wissen nicht verloren.
    Die Beispiele sind wirklich hübsch und gaben mir Hoffnung. Leider funktioniert folgender Aufruf nicht:

    $hash = ObjCreate("System.Collections.Hashtable")


    ;////Einträge hinzufügen///////////
    $hashhttp://www.autoit.de/dokumentation_…g_variables.htm.add ("Berlin", 3395189)

    ...weil ich unter XP arbeite? Oder gibt es einen anderen Grund? Fehlt ein Include?

    Wäre für jede Hilfe dankbar,

    Grüße
    Horst

  • System.Collections.ArrayList
    System.Collections.Queue
    System.Collections.Stack
    System.Collections.Hashtable
    --> das sieht mir nach .NET Namespace aus ;) Also wird wahrscheinlich das .NET-Framework benötigt, das auch ein paar COM-Objekte für einige Klassen installiert

  • Ja kann man damit vergleichen und prinzipiell mit allen anderen assoziativen Arrays auch.
    Der Thread ist schon bisschen älter weswegen ich oben noch das Scripting.Dictionary hinzugefügt habe.
    Das funktioniert genauso ist aber fast immer der Hash-Table vorzuziehen. Außer man will richtig viele Elemente unterbringen.

  • kann man bei dem hash auch mehrere felder benutzen?

    z.B. :

    [autoit]

    $hash.add ("Dresden", 504795, "PLZ", "Anzahl Mülltonnen")

    [/autoit]

    und dann auch entsprechend zugreifen? also z.B. "Anzahl Mülltonnen" in Dresden ?

    Danke und Gruß
    GerhardSchr

  • kann man bei dem hash auch mehrere felder benutzen?

    Prinzipiell handelt es sich um Schlüssel-Wert-Paare.
    Also erst einmal nur einzelne Values.
    Niemand hält dich allerdings davon ab als Value ein Array zu übergeben - dann kannst du soetwas umsetzen.
    Beispiel:

    [autoit]

    $hash = ObjCreate("System.Collections.Hashtable")

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

    Global $a_Temp[3] = [504795, 01129, 600000]
    $hash("Dresden") = $a_Temp

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

    $a_StadtInfos = $hash("Dresden")
    ConsoleWrite("Anzahl Mülltonnen in Dresden: " & $a_StadtInfos[2] & @CRLF)

    [/autoit]


    Da der Fall allerdings danach klingt eine Datenbank aufzubauen sollte man sich überlegen ob man nicht gleich auf eine Datenbank (in AutoIt ist z.B. SQLite integriert) ausweicht und man so effektiver an sein Ziel kommt.

  • Du hast dir viel Mühe gegeben, eine strukturierte Übersicht von Array-Alternativen zu erstellen
    und ich muss sagen, das ist dir echt gut gelungen.
    Hut ab. :thumbup:

    [autoit]


    Func Ulam($n)
    Return 1
    EndFunc

    [/autoit]


    Rekursion FTW :D

  • Listen in AutoIt 8o.. das hat echt was.

    Ich kann mich meinem Vorgänger nur anschließen,
    Hut ab für diese tolle Übersicht der Alternativen! :thumbup:

    "Je mehr Käse, desto mehr Löcher; je mehr Löcher, desto weniger Käse. Ergo: Je mehr Käse, desto weniger Käse. 8| "
    "Programmers never die: they just GOSUB without RETURN"
    "I tried to change the world but I couldn't find the source code."

  • Warum eigentlich nicht auch das RecordSet-Objekt (ADO) als Alternative zum Array nutzen?

    Spoiler anzeigen
    [autoit]

    AutoItSetOption('MustDeclareVars', 1)

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

    Dim Const $adInteger = 3
    Dim Const $adVarChar = 200
    Dim Const $adFilterNone = 0
    Dim Const $adSearchForward = 0
    Dim Const $adBookmarkFirst = 1
    Dim Const $adAffectCurrent = 1
    Dim Const $adPersistXML = 1
    Dim Const $adSaveCreateOverWrite = 2
    Dim Const $DefinedSize = 255

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

    Dim $err = ObjEvent('AutoIt.Error', '_ErrorHandler')
    Dim $rs = ObjCreate('ADODB.RecordSet')

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

    ; --- Aufbau der dynamischen Tabelle
    $rs.Fields.Append('ID', $adInteger)
    $rs.Fields.Append('Name', $adVarChar, $DefinedSize)
    $rs.Fields.Append('Vorname', $adVarChar, $DefinedSize)
    $rs.Fields.Append('Telefon', $adVarChar, $DefinedSize)

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

    $rs.Open()
    ; --- Tabelle befüllen
    $rs.AddNew()
    $rs('ID') = 1
    $rs('Name') = 'Dosenkohl'
    $rs('Vorname') = 'Hans'
    $rs('Telefon') = '099/999999'
    $rs.Update()

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

    $rs.AddNew()
    $rs('ID') = 2
    $rs('Name') = 'Wumpe'
    $rs('Vorname') = 'Klaus'
    $rs('Telefon') = '088/8888888'
    $rs.Update()

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

    $rs.AddNew()
    $rs('ID') = 3
    $rs('Name') = 'Dampf'
    $rs('Vorname') = 'Hans'
    $rs('Telefon') = '077/777777'
    $rs.Update()

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

    ConsoleWrite('Tabelle ausgeben' & @CRLF)
    _PrintTable()

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

    ; --- Tabelle sortieren
    $rs.Sort = 'Telefon'
    ConsoleWrite('Sortierte Tabelle ausgeben' & @CRLF)
    _PrintTable()

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

    ; --- Tabelle filtern
    $rs.Filter = 'Vorname = ''Hans'''
    ConsoleWrite('Gefilterte Tabelle ausgeben' & @CRLF)
    _PrintTable()

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

    ; --- Filterung entfernen
    $rs.Filter = $adFilterNone

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

    $rs.MoveFirst()
    ; --- Datensatz suchen
    $rs.Find('Vorname = ''Hans''')
    ConsoleWrite('Suchergebnis ausgeben' & @CRLF)
    If Not $rs.BOF And Not $rs.EOF Then
    While Not $rs.EOF
    ConsoleWrite(StringFormat('%s %s %s %s %s\n', _
    $rs('ID').Value, $rs('Name').Value, $rs('Vorname').Value, $rs('Telefon').Value))
    $rs.Find('Vorname = ''Hans''', 1)
    WEnd
    Else
    ConsoleWrite('Keine Übereinstimmung gefunden!' & @CRLF)
    EndIf
    ConsoleWrite(@CRLF)

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

    ; --- Einen Datensatz von der aktullen Position nach vorne springen
    $rs.Move(1, $adBookmarkFirst)
    If Not $rs.BOF And Not $rs.EOF Then
    ConsoleWrite('Der Datensatz ...' & @CRLF)
    ConsoleWrite(StringFormat('%s %s %s %s %s\n', _
    $rs('ID').Value, $rs('Name').Value, $rs('Vorname').Value, $rs('Telefon').Value))
    ConsoleWrite('... wird gelöscht!' & @CRLF)
    ; --- aktuellen Datensatz löschen
    $rs.Delete($adAffectCurrent)
    EndIf
    ConsoleWrite(@CRLF)
    _PrintTable()

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

    ; --- Tabelle persistent speichern
    Dim $stm = ObjCreate('ADODB.Stream')
    $rs.Save($stm, $adPersistXML)
    $stm.SaveToFile('c:\user.xml', $adSaveCreateOverWrite)

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

    ; --- Tabelle schliessen
    $rs.Close()
    $stm.Close()

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

    Func _PrintTable()
    $rs.MoveFirst()
    While Not $rs.EOF
    ConsoleWrite(StringFormat('%s %s %s %s %s\n', $rs('ID').Value, $rs('Name').Value, $rs('Vorname').Value, $rs('Telefon').Value))
    $rs.MoveNext()
    WEnd
    ConsoleWrite(@CRLF)
    EndFunc ;==>_PrintTable

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

    Func _ErrorHandler()
    ConsoleWrite(StringFormat('Fehlernr .....: %s\n', Hex($err.number, 8)))
    ConsoleWrite(StringFormat('Beschreibung .: %s\n', $err.description))
    ConsoleWrite(StringFormat('Skriptzeile ..: %s\n', $err.line))
    Return SetError(1)
    EndFunc ;==>_ErrorHandler

    [/autoit]