Was ist ein Array?

Am einfachsten lässt sich ein Array mit einer Tabelle vergleichen. Auch der Begriff Matrix ist in anderen Sprachen üblich.
Die einfachste Form ist eine einspaltige Liste. Nach oben sind physikalisch Grenzen gesetzt, aber selbst die sind mental kaum vorstellbar.
Ich beschränke mich hier auf Ein- und Zweidimensionale Array.

Inhalt:

Beginnen wir mit einem Ein-Dimensionalen Array

Dies entspricht einer einspaltigen Tabelle.


Bevor ich ein Array mit Daten füllen kann, muss ich es deklarieren, also einen Variablennamen vergeben und die Anzahl der Elemente bestimmen.
Es empfiehlt sich an den Beginn des Variablennamens 'a' oder 'ar' zu setzen um immer sofort zu wissen, dass dieses ein Array ist.

Jedes Element in einem Array wird über seinen Index angesprochen. Das ist gewissermaßen die Hausnummer des Elements.
Hierbei ist zu beachten, dass im Array der erste Index = 0 ist. Man spricht hier von einem Null-Basierten Index.

Deklarieren wir ein Array mit 5 Elementen:

    Local $arTest[5]    ; Die Anzahl der Elemente wird in eckigen Klammern hinter dem Variablennamen angegeben.

Der kleinste, deklarierbare Wert ist ein Array mit einem Element:

    Local $arTest[1]

Angesprochen wird dieses Element mit: $arTest[0]

[top] [1D] [2D]

Um nun Werte zuzuweisen, wird die Arrayvariable mit dem Index des Elements angegeben und dann der Wert zugewiesen.
Dran denken - Element Nr. 1 hat den Index 0.

    $arTest[0] = 'Wert 1'
    $arTest[1] = 'Wert 2'
    $arTest[2] = 'Wert 3'
    $arTest[3] = 'Wert 4'
    $arTest[4] = 'Wert 5'

Wer nicht mit dem Index 0 arbeiten möchte, kann an dieser Position ja einen Zähler platzieren oder einfach leer lassen.

Die identische Wertzuweisung kann ich auch in einer Schleife ausführen.
Hierbei lasse ich den Index in der Schleife bis zum Endwert erhöhen.
Da ich nicht immer weiß, wie viel Elemente das Array enthält, verwende ich die Funktion UBound() zur Größenbestimmung.
Für unser Array liefert: UBound($arTest) den Wert 5.
Das letzte Element muss also 1 kleiner als UBound sein, da wir mit 0 beginnen zu adressieren.

    For $i = 0 To UBound($arTest) -1
       
$arTest[$i] = 'Wert ' & $i +1    ; Da die Ziffer hinter Wert nicht mit 0, sondern mit 1 beginnt, muss ich 1 größer als der Schleifenzähler setzen
   
Next

[top] [1D] [2D]

Viele Funktionen geben als Ergebnis ein Array zurück. Dabei wird häufig die Arrayposition [0] genutzt um die Anzahl der Arrayelemente anzugeben.
Ein Bsp. hierfür ist StringSplit().
Nehmen wir an, wir haben einen String mit durch '|' getrennten Werten.

    $string = 'a|b|d|f|h|i|k'

Wir möchten jetzt jeden Wert einzeln haben:

    $arSplit = StringSplit($string, '|')

Und das ist jetzt der Inhalt von $arSplit

    $arSplit[0] = 7
    $arSplit
[1] = 'a'
    $arSplit
[2] = 'b'
    $arSplit
[3] = 'd'
    $arSplit[4] = 'f'
    $arSplit
[5] = 'h'
    $arSplit
[6] = 'i'
    $arSplit
[7] = 'k'

[top] [1D] [2D]

Es empfiehlt sich, wenn man mit Funktionen arbeitet die ein Array zurückgeben sollen, vor der Weiterverarbeitung zu prüfen ob auch ein Array vorhanden ist.
Bzw. auszuwerten ob das Array Werte enthält. Da StringSplit() im Fehlerfall ein Array mit dem Originalstring zurückgibt könnte das so aussehen:

    $arSplit = StringSplit($string, '|')
   
If
$arSplit[0] = 1 Then ; Wenn String nicht gesplittet wurde (Seperator nicht enthalten, String leer), dann Fehler
       
MsgBox(0, '', 'Fehler')
    Else
        For
$i = 1 To UBound(
$arSplit) -1    ; Hier könnte man auch $arSplit[0] statt UBound($arSplit) -1 verwenden, da die Anzahl dort geführt wird
       
    MsgBox(0, 'Ergebnis Splitten', 'Wert Nr.:' & $i & ' = ' &
$arSplit[$i])
        Next
    EndIf

[top] [1D] [2D]

Bei Funktionen, die nur im Erfolgsfall ein Array zurückgeben, empfiehlt sich folgende Überprüfung:

    $arReturn = Funktionsaufruf()   
     If (Not IsArray($arReturn )) Then    ; Wenn kein Array, dann Fehler

Der Ausdruck (Not IsArray($arReturn )) muss nicht zwingend in Klammern gesetzt werden. Es dient hier zur Verbesserung der Übersicht.

Anmerkung:
Auch wenn Funktionen ein Array zurückgeben, sollte die Arrayvariable vorher deklariert werden. Allerdings ist es hier ausreichend den Namen zu deklarieren. Die Größe des Array wird von der Funktion festgelegt.
Für StringSplit() ist dies nicht zwingend, aber _FileListToArray() bringt einen Fehler, wenn die Arrayvariable vorab nicht deklariert wurde. Also ist es günstiger sich generell anzugewöhnen, Variablen vorab zu deklarieren.

[top] [1D] [2D]

Beispiel:
Mit dem folgenden Beispiel will ich zeigen, wie man Programmieraufwand durch Einsatz eines Array verringern kann.

Eine GUI mit Controls wird deklariert. Die Controls sollen per Button wahlweise aktiv/deaktiv sein. Die Art der Controls lasse ich mal offen.

• Variante ohne Array

    Local $aktiv = True

    $GUI = GUICreate('Titel')
    $control1 = GUICtrlCreate...
    $control2
= GUICtrlCreate...
    $control3
= GUICtrlCreate...
    $control4
= GUICtrlCreate...
    $control5
= GUICtrlCreate...
    $control6
= GUICtrlCreate...
    $control7
= GUICtrlCreate...
    $button
   = GUICtrlCreate...
    ;...
   
If $msg = $button Then _SwitchActiv()
    ;...

    Func _SwitchActiv()
       
Local $state
      
 If $aktiv Then
           
$state = $GUI_DISABLE   ; aktueller Status 'aktiv' - dann 'disable' setzen
        Else
            $state = $GUI_ENABLE    ; aktueller Status 'inaktiv' - dann 'enable' setzen
        EndIf
        $aktiv = Not $aktiv                  ; Wert umkehren (True zu False und umgekehrt)
        GUICtrlSetState($control1, $state)
       
GUICtrlSetState($control2, $state)
       
GUICtrlSetState($control3, $state)
       
GUICtrlSetState($control4, $state)
       
GUICtrlSetState($control5, $state)
       
GUICtrlSetState($control6, $state)
       
GUICtrlSetState($control7, $state)
  
 EndFunc ; ==>_SwitchActiv

• Variante mit Array

    Local $aktiv = True
   
Local $arControl[8]

    $GUI = GUICreate('Titel')
    $arControl[0] = GUICtrlCreate...
    $arControl
[1] = GUICtrlCreate...
    $arControl
[2] = GUICtrlCreate...
    $arControl
[3] = GUICtrlCreate...
    $arControl
[4] = GUICtrlCreate...
    $arControl
[5] = GUICtrlCreate...
    $arControl
[6] = GUICtrlCreate...
    $arControl
[7] = GUICtrlCreate... ; Button
    ;...
   
If $msg = $arControl[7] Then _SwitchActiv()
    ;...

    Func _SwitchActiv()
       
Local $state
      
 If $aktiv Then
           
$state = $GUI_DISABLE
        Else
            $state = $GUI_ENABLE
        EndIf
        $aktiv = Not $aktiv
       
For $i = 0 To 6
           
GUICtrlSetState($arControl[$i], $state)
       
Next
  
 EndFunc ; ==>_SwitchActiv

 

Es ist sichtbar, dass der Einsatz eines Array mit steigender Anzahl von Controls immer effektiver wird. Zum Setzen des Status ist, egal wieviel Controls vorhanden sind, nur eine Schleife mit 3 Codezeilen nötig.
Es erfordert natürlich etwas abstraktes Denken um sich hinter Array+Index etwas vorstellen zu können. Zum Anfang empfehle ich, einfach jede Zeile im Code mit einem kurzen Kommentar zu versehen. Dann kann man sich viel schneller einlesen.
Auch sollte der Name des Array immer aussagekräftig sein. Skriptpuristen schreiben da gerne mal: $a1, $a2 etc. Das spart zwar Schreibarbeit, beeinträchtigt aber die Lesbarkeit des Codes. Und gerade, wenn ich vielleicht um Hilfe zu suchen, mein Skript jemand Anderem vorlege, soll dieser auch die Chance haben sich zügig einzulesen.

[top] [1D] [2D]

Das Mehrdimensionale Array am Beispiel eines 2-Dimensionalen Array

Das 2-Dimensionale Array kann man vergleichen mit einer mehrspaltigen Tabelle. Eine Dimension entspricht dann den Zeilen, während die andere die Spalten verkörpert.
Im Allgemeinen ist es üblich, dass die erste Dimension die Zeilen (Anzahl Elemente) und die zweite Dimension die Spalten (Werte je Element) enthält.

[top] [1D] [2D]

Daraus ergibt sich folgende Deklaration:

    Local $ar2Dimensional[$ElementeZahl][$Spaltenzahl]

Hier muß das kleinste deklarierbare Array 1 Element und 1 Spalte enthalten. Natürlich macht es wenig Sinn, ein mehrdimensionales Array mit nur einer Spalte zu deklarieren, dann kann ich ja gleich ein 1-D Array verwenden.
Also ist die kleinste 'sinnvolle' Deklaration für ein 2-D Array: 1 Element und 2 Spalten.

Hier mal ein Array mit 5 Elementen und 2 Spalten:

    Local $ar2D[5][2]

[top] [1D] [2D]

Auch hier gilt selbstverständlich für Zeilen- und auch Spaltenwert, dass das erste Element über den Index 0 angesprochen wird.
Ich weise jetzt allen Elementen Werte zu:

Zeile 1
    $ar2D[0][0] = 'Zeile1/Spalte1'
   
$ar2D[0][1] = 'Zeile1/Spalte2'

Zeile 2
    $ar2D[1][0] = 'Zeile2/Spalte1'
   
$ar2D[1][1] = 'Zeile2/Spalte2'

Zeile 3
    $ar2D[2][0] = 'Zeile3/Spalte1'
   
$ar2D[2][1] = 'Zeile3/Spalte2'

Zeile 4
    $ar2D[3][0] = 'Zeile4/Spalte1'
   
$ar2D[3][1] = 'Zeile4/Spalte2'

Zeile 5
    $ar2D[4][0] = 'Zeile5/Spalte1'
   
$ar2D[4][1] = 'Zeile5/Spalte2'

Nun kommt der Punkt, an dem die 'Knoten' im Gehirn entstehen.

Ich möchte ja den Vorteil des Array nutzen und in einer Schleife alles abarbeiten.
Aber wie muß ich vorgehen?

Am Besten überlege ich, wie ich von Hand Daten in eine Tabelle eingebe:
    - Schreib Zeile 1, Spalte 1
    - dann schreib Zeile 1, Spalte 2
    - dann die nächste Zeile, Spalte 1 und
    - in dieser Zeile die Spalte 2
    - bis zur letzten Zeile

Als Pseudo-Code:
    Beginne bei StartZeile bis EndZeile
        Schreib Spalte 1 dieser Zeile
        Schreib Spalte 2 dieser Zeile
    Nächste Zeile

Bei 2 Spalten ist das so machbar. Habe ich aber mehrere Spalten, deren Anzahl ich auch vorab nicht weiß, müssen die Spalten auch in einer Schleife bearbeitet werden:
    Beginne bei StartZeile bis EndZeile
        Beginne bei erster Spalte bis letzte Spalte
            Schreib Spaltenwert
        Nächste Spalte
    Nächste Zeile

Und so sieht das in AutoIt-Code aus:

    For $i = 0 To UBound($ar2D) -1                            ; $i ist der Zähler für die Zeilen
        For $k = 0 To UBound($ar2D, 2) -1                   ; $k ist der Zähler für die Spalten
            $ar2D[$i][$k] = 'Zeile' & $i & '/Spalte' & $k
        Next
    Next

Wie ihr seht verwende ich in der äußeren Schleife UBound($ar2D) und in der inneren Schleife UBound($ar2D, 2) .
Die äußere Schleife gilt für die erste Dimension, deren Wert standardmäßig von der Funktion UBound( ) zurückgegeben wird.
Um die Spaltenzahl zu ermitteln, muß ich aber der Funktion UBound( ) mitteilen, für welche Dimension ich den Wert ermitteln möchte, in unserem Fall ist dies die 2.
Nicht durcheinander kommen. Hier wird nicht der Index verwendet! Für die erste Dimension die 1, für die zweite die 2 usw.

Ich erwähnte oben, dass es üblich ist, dass die erste Dimension die Zeilen (Anzahl Elemente) und die zweite Dimension die Spalten (Werte je Element) enthält.
Das ist aber nicht zwingend! Man kann ein Array auch genau entgegengesetzt bestücken. Also die Elemente in den Spalten und zugehörige Werte in den Zeilen.
Darauf gehe ich jetzt aber nicht näher ein, man muß halt in der Schleifenabarbeitung dann in der äußeren Schleife die Spalten und in der inneren Schleife die Zeilen führen.

[top] [1D] [2D]

Auch einige Funktionen liefern von Haus aus ein 2-D Array zurück.

Nehmen wir als Bsp. IniReadSection("filename", "section")
So sieht unsere INI-Datei aus:

    [sektion]
    schluesselA=1
    schluesselB=2
    schluesselC=3
    schluesselD=4

Jetzt lesen wir die Sektion ein:

    #include <array.au3>
   
Local $val                                                                    ; Variable für Array deklarieren
    $val = IniReadSection($pathINI, "sektion")             ; Sektion einlesen
   
If (Not IsArray($val)) Then                                          ; Wenn zurückgegebene Variable kein Array ist
        MsgBox(0, '', 'INI-Sektion konnte nicht gelesen werden')
        Exit
    EndIf

    _ArrayDisplay($val, 'Inhalt INI-Sektion: [sektion]')    ; eingelesenes Array anzeigen

Schauen wir uns den Inhalt des Array an:

    $val[0][0] = 4    ; Anzahl der eingelesenen Schlüssel-Wert Paare

    $val[1][0] = 'schluesselA'    ; Name des Schlüssels
   
$val[1][1] = 1                        ; Wert des Schlüssels

    $val[2][0] = 'schluesselB'
   
$val[2][1] = 2

    $val[3][0] = 'schluesselC'
   
$val[3][1] = 3

    $val[4][0] = 'schluesselD'
   
$val[4][1] = 4

Möchte ich jetzt auf den Wert von 'schluesselC' zugreifen, muß ich das Array nach dem Schlüssel durchsuchen und mir den zugehörigen Wert ausgeben lassen:

    Local $SuchWert, $SuchSchluessel = 'schluesselC'
    For $i = 1 To UBound($val) -1
        If $val[$i][0] = $SuchSchluessel Then
            $SuchWert = $val[$i][1]
            ExitLoop
        EndIf
    Next

    MsgBox(0, '', 'gesuchter Wert ist: ' & $SuchWert)

Ich vergleiche also in jedem Element des Array ob der enthaltene Schlüsselname (Position[n][0]) mit meinem gesuchten Namen übereinstimmt.
Wird der Schlüssel gefunden, lese ich den zugehörigen Wert aus (Position[n][1]).

[top] [1D] [2D]

Array - Statisch oder Dynamisch

Ein Array ist statisch, wenn wir eine feste Größe für das Array definieren und dann damit arbeiten.
Dynamisch ist ein Array dann, wenn wir zur Laufzeit (also während das Programm abgearbeitet wird) die Größe des Array anpassen.

    • statisch

    Local $array[20]                                                     ; Array hat 20 Elemente
   
Local $zaehler = -1                                                ; Indexwert vor erstem Eintrag

    Ich kann jetzt bis zu 20 Werte in das Array eintragen. Der letzte Wert ist also: $array[19] = 'letzter Wert'
    Immer wieder dran denken: Array-Adressierung beginnt mit Index 0.
    Ich werde das sicher noch öfter wiederholen, denn erfahrungsgemäß sind Indexfehler die häufigsten Fehler bei der Arbeit mit Array.

    ; im Programm gibt der User Daten in ein Input ein, die dem Array zugefügt werden sollen
    $newData = GUICtrlRead($Input)
    If $newData <> '' Then                                         ; prüfen ob nicht leer
       
$zaehler += 1                                                   ; Indexwert um eins erhöhen, für ersten Eintrag jetzt 0
       
If $zaehler < 20 Then                                       ; wenn Index kleiner als 20 ist   
       
    $array[$zaehler] = $newData                     ; Daten an Indexposition eintragen
       
Else                                                                   ; sonst Fehlermeldung
           
MsgBox(0, 'FEHLER', 'Keine weiteren Einträge möglich! - Array ist voll.')
        EndIf

    EndIf
 

    • dynamisch

    Local $array[1]                                                    ; Array hat zum Programmstart 1 Element

    $newData = GUICtrlRead($Input)
    If $newData <> '' Then                                        ; prüfen ob nicht leer
        ; der erste Eintrag soll in das bestehende 1. Array-Element eingetragen werden, z.Zt. das letzte
        ; für weiter Einträge muß das Array vorher um ein Element vergrößert werden

        If $array[Ubound($array)-1] <> '' Then         ; ist das letzte Element NICHT leer (dann ist es NICHT das erste)
            ReDim $array[Ubound($array)+1]           ; Arraygröße neu: 1 größer als aktuelle Größe Ubound($array)
        EndIf
        $array[Ubound($array)-1] = $newData       ; Daten in das letzte Element schreiben, im ersten Durchlauf ist dies das erste.
    EndIf

    Die aktuelle Arraygröße ist immer mit Ubound($array) feststellbar.
    Mit ReDim wird das Array neu bestimmt. Wichtig dabei - die enthaltenen Daten gehen nicht verloren.
    Wichtig nochmal für das Befüllen des ersten Elements. Bei der Array-Deklaration ist $array[0] ohne Inhalt.
    Dieses Element ist zum Programmstart auch das letzte Element, weil:
        Ubound($array) gibt 1 zurück.
        Da der Index für das letzte Element Obergrenze -1 ist, gilt: $Index = Ubound($array) -1 ; ( 1 -1 = 0 )
        Im ersten Durchlauf ist somit $array[Ubound($array)-1] identisch mit $array[0], dem ersten Element.
    Die Inhaltsprüfung ergibt KEINEN Inhalt und somit wird die Arraygröße NICHT verändert, sondern in das letzte Element geschrieben.
    In allen weiteren Durchläufen ist das letzte Element MIT Inhalt, somit wird das Array um ein Element vergrößert und dann in das neue,
    letzte Element geschrieben.

Es läßt sich nicht generell sagen, wann man mit statischen und wann mit dynamischen Array arbeiten soll.
Ein Entscheidungskriterium ist die Datenmenge. Die Neudeklaration der Arraygröße beansprucht natürlich auch Zeit.
Insofern kann es durchaus günstiger sein, einfach vorab ein Array mit z.B. 1.000 Elementen zu definieren, wenn man weiß, dass diese Anzahl nicht überschritten wird.

[top] [1D] [2D]

Deklaration mit Wertzuweisung

Es können bei der Deklaration des Array sofort Werte zugewiesen werden. Hier die Vorgehensweise für 1D-Array und 2D-Array.

Local
$aTest1[5] = [1,2,3,4,5]

Local $aTest2[5][2] = [ [1,1], [2,2], [3,3], [4,4], [5,5] ]
Local $aTest3[5][3] = [ [1,1,1], [2,2,2], [3,3,3], [4,4,4], [5,5,5] ]

[top] [1D] [2D]

Minimierung Globaler Variablen durch Array

Die Anzahl Global  deklarierter Variablen sollte man so gering, wie möglich halten. Falls es erforderlich ist Variablen Global zu verwenden, bietet es sich an, dafür ein Array zu nutzen.
Hier im Bsp. werden die ID's für GUI und GUI-Ctrls im Array hinterlegt. Vorab werden die GUI/ GUICtrl -Variablen mit Enum durchnummeriert.  Enum startet (wenn nicht anders vorgegeben) mit 0, das ist praktisch, da das erste Arrayelement den Index 0 hat. Wir beenden die Enumeration mit der Variablen
$Anzahl, welche uns die Anzahl der Arrayelemente angibt.

Enum $guiMain, $btRead, $btClose, $btSafe, $inBetrag, $inWaehrung, $Anzahl
Global $aGui[$Anzahl]

Nun werden wie üblich GUI und GUICtrl's erstellt. Die Reihenfolge spielt keine Rolle, da der verwendete Variablenname aus der Enumeration eindeutig die Position im Array bestimmt.

$aGui[$guiMain] = GUICreate('Test')
$aGui[$btRead] = GUICtrlCreateButton('Read'...)
$aGui[$btClose] = GUICtrlCreateButton('Close'...)
$aGui[$btSafe] = GUICtrlCreateButton('Safe'...)
$aGui[$inBetrag] = GUICtrlCreateInput('Betrag'...)
$aGui[$inWaehrung] = GUICtrlCreateInput('Währung'...)

Der Vorteil:
Obwohl die ID's im Array gespeichert sind, kann ich sie mit: Index = Variablenname verständlich ansprechen. Es ist durchaus vergleichbar mit einem assoziativen Array. Das erleichtert vor allem bei großen Skripten das Lesen.

Auch hier läßt sich aber Deklaration und Wertzuweisung in einem Schritt erledigen.
Wichtig!! Dann muß aber zwingend darauf geachtet werden, dass alle Elemente genau in der Reihenfolge der Enumeration zugewiesen werden!

Global $aGui[$Anzahl] = [ _
GUICreate('Test'), _
GUICtrlCreateButton('Read'...), _
GUICtrlCreateButton('Close'...), _
GUICtrlCreateButton('Safe'...), _
GUICtrlCreateInput('Betrag'...), _
GUICtrlCreateInput('Währung'...)]


Der weitere Zugriff gestaltet sich, wie üblich
z.B.

While True
    Switch GUIGetMsg()
        Case $aGui[$btClose], $GUI_EVENT_CLOSE
            Exit
        Case $aGui[$btRead]
            ConsoleWrite(GUICtrlRead($aGui[$inBetrag]) & '  ' & GUICtrlRead($aGui[$inWaehrung]) & @CRLF)
        Case $aGui[$btSafe]
            ; Speicherfunktion
    EndSwitch
WEnd

[top] [1D] [2D]

Dies soll euch den Einstieg in die Arbeit mit Arrays erleichtern. Ich habe mich bewußt etwas beschränkt um nicht mit zu vielen Details Verwirrung zu stiften.
Ich würde mich aber freuen, wenn ihr mir mitteilt, zu welchen Punkten ihr nähere Erläuterungen wünscht. Wenn man erst mal mit umgehen kann ist es gar nicht so einfach, sich auf die Probleme der Anfangszeit zurück zu besinnen.
Eure Fragen mit den Erklärungen, würde ich dann in Form einer FAQ anhängen.

Euer BugFix        Kontakt: Mail BugFix