Mehrdimensionale Arrays
Allgemeines
Ein Beispiel für ein zweidimensionales Array ist eine sogenannte
Matrix. Dabei handelt es sich zunächst einfach um eine
Anordnung von Zahlen (oder Variablen oder Termen oder...) in einem Feld, wobei
jeder Eintrag durch zwei Kennziffern (Indizes) bestimmt ist.
Beispiel einer 2x3-Matrix
(2 Zeilen, 3 Spalten):
Um eine einzelne Variable zu beschreiben, setzt man Zeile und Spalte
als Index an den Namen der Matrix, z.B.:
Will man nun ein Perl-Programm schreiben, das mit Matrizen
arbeiten soll, muß man sich überlegen, wie man sie geeignet
speichert. Da Arrays ein geordnetes eindimensionales
(ein Index) Schema darstellen, ließe sich
eine Matrix wohl aus der Kombination von Arrays repräsentieren.
[Seitenanfang]
Wie es nicht geht
Die einfachste Idee scheint zu sein, die Zeilen jeweils in einzelnen
Arrays zu speichern und dann diese Zeilen-Arrays in ein Matrix-Array
einzusetzen:
#!/usr/local/bin/perl -w
use strict;
my @zeile_1 = ( 'a', 'b', 'c' ); my @zeile_2 = ( 'd', 'e', 'f' );
my @matrix = ( @zeile_1, @zeile_2 ); # 6-elementiges Array
|
|
Obiger Code erzeugt keineswegs eine zweidimensionale Matrix in
@matrix
. In der letzten Zeile werden nämlich
zuerst die beiden Zeilen-Arrays @zeile_1
und
@zeile_2
als Listen dargestellt, die
dann vor der Zuweisung zu einer
6-elementigen Liste vereinigt
werden. Die letzte Zeile des obigen Programms ist also äquivalent zu:
my @matrix = ( 'a', 'b', 'c', 'd', 'e', 'f' );
|
|
Die Ursache für dieses Verhalten liegt darin begründet,
daß Arrays in Perl grundsätzlich nur skalare Größen
enthalten, aber keine Arrays oder Hashes (sie werden, wie oben beschrieben,
vorher umgewandelt).
[Seitenanfang]
Verwendung von Referenzen
Einen Ausweg aus dem Dilemma bieten Referenzen, da sie skalare
Variablen sind, aber auf beliebige Datentypen (so auch Arrays)
"zeigen" können.
#!/usr/local/bin/perl -w
use strict;
my @zeile_1 = ( 'a', 'b', 'c' ); my @zeile_2 = ( 'd', 'e', 'f' );
my $ref_zeile_1 = \@zeile_1; my $ref_zeile_2 = \@zeile_2;
my @matrix = ( $ref_zeile_1, $ref_zeile_2 );
|
|
Nun enthält das Array @matrix
zwei (skalare) Elemente,
die ihrerseits jeweils eine Referenz auf ein Zeilen-Array sind.
Wie kann man nun auf die einzelnen Matrixelemente zugreifen?
Die Elemente $matrix[0]
und $matrix[1]
enthalten jeweils eine Referenz auf ein Array, so daß nach
der Dereferenzierung die Zeilen-Arrays zur Verfügung stehen.
An dieser Stelle sei noch einmal darauf hingewiesen, daß in Perl
Array-Indizes üblicherweise bei 0 anfangen. Man sollte nicht die
Variable $[
auf
1 setzen, um bei 1 mit der Zählung zu
beginnen, sondern besser die Elemente oder Zeilen-Arrays gezielt an die
Positionen 1,2,... der jeweiligen Arrays schreiben. Der Einfachheit
halber wird in den Beispielen hier darauf verzichtet,
so daß zu beachten ist, daß von den Matrix-Indizes
immer jeweils 1 zu subtrahieren ist, um die Array-Indizes zu erhalten.
Ein ausführliches Beispiel sieht dann so aus:
#!/usr/local/bin/perl -w
use strict;
my @zeile_1 = ( 'a', 'b', 'c' ); my @zeile_2 = ( 'd', 'e', 'f' );
my $ref_zeile_1 = \@zeile_1; my $ref_zeile_2 = \@zeile_2;
my @matrix = ( $ref_zeile_1, $ref_zeile_2 );
my $ref_1 = $matrix[0]; @zeile_1 = @$ref_1;
my $ref_2 = $matrix[1]; @zeile_2 = @$ref_2;
print "1) @zeile_1\n"; print "2) @zeile_2\n";
|
|
Der Zugriff läßt sich natürlich auch kompakter
programmieren:
my @matrix = ( $ref_zeile_1, $ref_zeile_2 );
print "1) @{$matrix[0]}\n"; print "2) @{$matrix[1]}\n";
|
|
Wegen der Präzedenzregeln müssen bei den Dereferenzierungen
hier geschweifte Klammern gesetzt werden (ansonsten würde Perl
zuerst versuchen, $matrix
zu dereferenzieren und erst
dann dort das Element mit dem entsprechenden Index suchen).
Mit Hilfe dieses Mechanismus lassen sich auch gezielt einzelne
Matrixelemente auslesen oder mit Werten besetzen:
#!/usr/local/bin/perl -w
use strict;
my @zeile_1 = ( 'a', 'b', 'c' ); my @zeile_2 = ( 'd', 'e', 'f' ); my $ref_zeile_1 = \@zeile_1; my $ref_zeile_2 = \@zeile_2; my @matrix = ( $ref_zeile_1, $ref_zeile_2 );
print "Matrix(1,2) = ${$matrix[0]}[1]\n";
${$matrix[1]}[2] = 'x'; print "1) @{$matrix[0]}\n"; print "2) @{$matrix[1]}\n";
|
|
Matrix(1,2) = b 1) a b c 2) d e x
|
|
Eine alternative Schreibweise für den Zugriff auf ein
einzelnes Element bietet der Pfeil-Operator
"->
" (nicht zu verwechseln mit "=>
"
als Kommaersatz):
print "Matrix(1,2) = $matrix[0]->[1]\n";
$matrix[1]->[2] = 'x';
|
|
Und auch dies läßt sich noch verkürzen, da Perl
zwischen zwei aufeinander folgenden Klammern (eckig oder geschweift)
automatisch einen Pfeil-Operator setzt. Dadurch läßt sich
eine sehr intuitive und übersichtliche Schreibweise erreichen:
print "Matrix(1,2) = $matrix[0][1]\n";
$matrix[1][2] = 'x';
|
|
[Seitenanfang]
Anonyme Arrays
Wie der Name schon vermuten läßt, handelt es sich dabei um
Arrays, die keinen eigenen Variablennamen besitzen. Die einzige
Möglichkeit, auf den Inhalt zuzugreifen, besteht in einer
Referenz auf dieses Array. Erzeugen kann man ein solches Array, indem
man bei einer Liste eckige anstelle von runden Klammern verwendet.
Der Rückgabewert ist dann eine Referenz auf diese Liste.
Beispiel:
#!/usr/local/bin/perl -w
use strict;
my @array = ( 10, 20, 30, 40 ); # normales Array my $ref_array = [ 10, 20, 30, 40 ]; # anonymes Array
|
|
Da ein solches anonymes Array eine Referenz liefert, kann man daraus
direkt mehrdimensionale Felder erstellen. Die weiter oben als Beispiel
verwendete Matrix ließe sich dann auch so erzeugen:
#!/usr/local/bin/perl -w
use strict;
my @matrix = ( [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] );
|
|
Noch einmal zur Erinnerung: würde man hier runde statt eckige
Klammern verwenden, erhielte man ein einfaches 6-elementiges Array
in @matrix
.
Auf die Matrixeinträge kann hier genauso zugegriffen werden
wie weiter oben bei den benannten Arrays beschrieben.
Ein Beispiel, wie man die gesamte Matrix ausgeben kann:
#!/usr/local/bin/perl -w
use strict;
my @matrix = ( [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] );
foreach my $ref_zeile (@matrix) { foreach my $spalte (@$ref_zeile) { print "$spalte " } print "\n"; }
|
|
Da eine solche zweidimensionale Datenstruktur letztlich auf
(eindimensionalen) Arrays beruht, kann man sie mit Hilfe bekannter
Funktionen wie push()
oder pop()
dynamisch verändern. So läßt sich die oben
definierte Matrix beliebig bearbeiten:
#!/usr/local/bin/perl -w
use strict;
my @matrix = ( [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] );
pop( @{$matrix[1]} ); # 'f' entfernen unshift( @{$matrix[0]}, 'M' ); # 'M' einfügen
push(@matrix, [ 'g', 'h', 'i' ] ); # neue 3.Zeile
foreach my $ref_zeile (@matrix) { foreach my $spalte (@$ref_zeile) { print "$spalte " } print "\n"; }
|
|
[Seitenanfang]