Mehrdimensionale Arrays

[ vorherige Seite ] [ Titelseite ] [ Inhalt ] [ Index ] [ nächste Seite ]


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.

[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";
1) a b c
2) d e f

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";
}
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

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";
}
M a b c 
d e 
g h i

[Seitenanfang]


[ vorherige Seite ] [ Titelseite ] [ Inhalt ] [ Index ] [ nächste Seite ]

Autor: Eike Grote Version: 2.06 (15.9.2013)