Mehrdimensionale Arrays

[ <= ] [ HOME ] [ INHALT ] [ INDEX ] [ => ]

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):

A= (
a b c
d e f
)

Um eine einzelne Variable zu beschreiben, setzt man Zeile und Spalte als Index an den Namen der Matrix, z.B.:

A  = b
1,2
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.


[ <- ] [ HOME ] [ INHALT ] [ INDEX ] [ -> ]

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

@zeile_1 = ( 'a', 'b', 'c' );
@zeile_2 = ( 'd', 'e', 'f' );

@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:

@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 Hashe (sie werden, wie oben beschrieben, vorher umgewandelt).


[ <- ] [ HOME ] [ INHALT ] [ INDEX ] [ -> ]

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

@zeile_1 = ( 'a', 'b', 'c' );
@zeile_2 = ( 'd', 'e', 'f' );

@matrix = ( \@zeile_1, \@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 auf dieser Seite 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

@zeile_1 = ( 'a', 'b', 'c' );
@zeile_2 = ( 'd', 'e', 'f' );

@matrix = ( \@zeile_1, \@zeile_2 );

$ref_1 = $matrix[0];
@zeile_1 = @$ref_1;

$ref_2 = $matrix[1];
@zeile_2 = @$ref_2;

print "1) @zeile_1\n";
print "2) @zeile_2\n";

1) a b c
2) d e f

Der Zugriff läßt sich natürlich auch kompakter programmieren:

@matrix = ( \@zeile_1, \@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 und mit Werten besetzen:

#!/usr/local/bin/perl -w

@zeile_1 = ( 'a', 'b', 'c' );
@zeile_2 = ( 'd', 'e', 'f' );
@matrix = ( \@zeile_1, \@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';


[ <- ] [ HOME ] [ INHALT ] [ INDEX ] [ -> ]

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

@array     = ( 10, 20, 30, 40 );     # normales Array
$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

@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

@matrix = ( [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] );

foreach $ref_zeile (@matrix) {
    foreach $spalte (@$ref_zeile) { print "$spalte " }
    print "\n";
}

a b c 
d e f 

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

@matrix = ( [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ] );

pop( @{$matrix[1]} );                 # 'f' entfernen
unshift( @{$matrix[0]}, 'M' );        # 'M' einfügen

push(@matrix, [ sort( 'i', 'h', 'g' ) ] );  # 3.Zeile

foreach $ref_zeile (@matrix) {
    foreach $spalte (@$ref_zeile) { print "$spalte " }
    print "\n";
}

M a b c 
d e 
g h i

Wie man sieht, wird auch der (Array-)Rückgabewert einer Funktion (hier: sort()) durch [...] in ein anonymes Array umgewandelt.


[ <= ] [ <- ] [ HOME ] [ INHALT ] [ INDEX ] [ -> ] [ => ]

Autor: Eike Grote Letzte Änderung: 06.09.1998