Webbasierte Adressdatenbank

Komplexe Datenstrukturen

Referenzen
Perl hat sich traditionell auf lineare Datenstrukturen konzentriert. Es ist in der Regel auch das, was benötigt wird. Gelegentlich möchte man aber komplexere Datenstrukturen verwenden, dies ist jetzt in Perl 5 relativ einfach mit "Referenzen" machbar. Neben der normalen Möglichkeit Variablen mit ihrem Namen anzusprechen, gibt es in Perl "Referenzen auf Datentypen" d. h. intelligente Zeiger auf Datentypen. Damit lassen sich sehr einfach Arrays von Arrays (List of Lists - LoL), Arrays von Hashes (LoH), Hashes von Hashes (HoH) oder noch komplexere Datenstrukturen erzeugen. Außerdem gibt es auch Referenzen auf Funktionen. Wir wollen hier zum einen die allgemeinen Verfahren zum "Referenzieren" bzw. zum "Dereferenzieren" darstellen, zum Anderen werden wir uns im Beispiel auf  LoL  beschränken, da diese Datenstruktur in der ersten Variante unserer Adressdatenbank Verwendung findet wird.
Die nachfolgende Tabelle zeigt, wie Referenzen erzeugt und verwendet werden:

  Verfahren     Erklärung  
  $scalarref   =   \$scalar;  

  $scalar   =   $$scalaref;  
  $scalar   =   ${$scalarref};  
  Skalar   ->   Skalarreferenz  

  Skalarreferenz   ->   Skalar  
  wie oben  
  $arrayref  =  \@array;  

  @array  =  @$arrayref;  
  @array  =  @{$arrayref};  

  $element  =  S{$arrayref}[3];  
  $element  =  $arrayref->[3];  
  Array  ->  Arreayreferenz  

  Arrayreferenz   ->  Array  
  wie oben  

  Arrayreferenz  ->  einzelnes Element  
  wie oben  
  $hashref  =  \%hash;  

  %hash  =  %$hashref;  
  %hash  =  %{$hashref};  

  $wert  ${$hashref}{'Schlüssel'};  
  $wert  =  $hashref->{'Schlüssel'};  
  Hash  ->  Hashreferenz  

  Hashreferenz  ->  Hash  
  wie oben  

  Hashreferenz  ->  Einzelner Wert  
  wie oben  
  $funcref  =  \&func  

  &$funcref();  
  $funcref->();  
  Funktion  ->  Funktionsrerefenz  

  Funktionsreferenz  ->  Aufruf der Funktion  
  wie oben  

Verwendet man Refrenzen von Arrays oder Hashes um auf einzelne Elemente oder Werte zuzugreifen, sollte vorwiegend der Pfeiloperator  ->  benutzt werden, da hier die Verwendung der Referenz deutlicher zu Tage tritt.

Beispiel LoL
Im Kapitel Zerlegen von Datensäzen heben wir gesehen, wie man einen Datensatz als String mit Trennzeichen erzeugt und in einer Datei abspeichert. Unsere Adressdatenbank wird diese Methode verwenden um die Adressdatensätze zu speichern. Wie können wir nun eine solche Struktur aus dem File wieder einlesen und z.B. zuerst nach Nachname und bei Gleichheit noch nach Vorname sortieren, bevor wir die Daten ausgeben? Am Besten funktioniert das mit LoL. Hier nun einige Code Schnippsel, welche die Verwendung einer LoL zeigen:

Zusammensetzen einer LoL

    @LoL = (
             [ "fred", "barney" ],
             [ "george", "jane", "elroy" ],
             [ "homer", "marge", "bart" ],
           );
    

Man beachte die eckigen Klammern um die einzelnen Zeilenarrays. Dies erzeugt automatisch eine Arrayreferenz!

Generierung einer LoL

    # Aus einer Datei
    while (<FILE>) {
        push @LoL, [ split ];
    }
    

Auch hier steht das mit  split  erzeugte Zeilenarray in eckigen Klammern um eine Arrayreferenz zu erzeugen. Die Funktion split  wird hier ganz ohne Argumente verwendet, was bedeutet, der aufzutrennende String steht in  $_ , und als Trennzeichen werden Whitspaces  /\s+/  verwendet, nachdem alle führenden Whitespaces entfernt wurden.

    # Zu einer existierenden Liste hinzufügen
    push @{ $LoL[0] }, "wilma", "betty";
    

Wenn wir einem Zeilenarray einer LoL etwas mit  push  hinzufügen wollen, müssen wir das Zeilenarray derefrenzieren, da eine LoL nicht die Zeilenarrays als echte Arrays beinhaltet, sonder als Arrayreferenzen!

Zugriff und Ausgabe von LoL

    # Ein Element
    $LoL[0][0] = "Fred";

    # Ein Anderes Element
    $LoL[1][1] =~ s/(\w)/\u$1/;

    # Ausgabe des gesamten Dingsdas mit Referenzen
    for $array_ref ( @LoL ) {
        print "\t  @$array_ref \n";
    }
    
    # Ausgabe des gesamten Dingsdas mit Indizes
    for $i ( 0 .. $#LoL ) {
        print "\t  @{$LoL[$i]} \n";
    }

    # Alle Elemente nacheinander ausgeben
    for $i ( 0 .. $#LoL ) {
        for $j ( 0 .. $#{$LoL[$i]} ) {
            print "element $i $j is $LoL[$i][$j]\n";
        }
    }
    

Die letzten zwei  for  Schleifen nutzen die Eingenschaft von  $#LoL  den Index des Letzten Elementes des Arrays zurückzugeben.

Beispiel Adressen
So, jetzt können wir uns wieder unserer Adressdatenbank zuwenden. Nehmen wir an, wir hätten folgende Datensätze in der Datei  adress.dat  stehen:

    Feuerstein|Fred|fred@irgendwo.com
    Geröllheimer|Betty|betty@irgendwo.anders.com
    Feuerstein|Wilma|wilma@irgendwo.com
    Geröllheimer|Barney|barney@irgendwo.anders.com
    

Jetzt wollen wir die Datei in eine LoL einlesen, sortieren, wie oben beschrieben und ausgeben:

     1:  #!/usr/bin/perl -w
     2:
     3:  use strict;
     4: 
     5:  my (@LoL, $array_ref, @sortetLoL, $i, $j);
     6:  my $file = "adress.dat";
     7:
     8:  open (FILE, "<$file") 
     9:      || die "Kann File $file nicht öffnen: $!";  # File zum Lesen öffnen
    10: 
    11:  while (<FILE>) {
    12:      chomp;                     # einlesen und Zeilenvorschub entfernen
    13:      push @LoL, [ split /\|/ ]; # an | auftrennen und an LoL anhängen
    14:  }
    15:
    16:  close (FILE) || die "Kann File $file nicht schließen: $!";
    17:  
    18:  @sortetLoL = sort { $a->[0] cmp $b->[0]  # Name
    19:                              ||
    20:                      $a->[1] cmp $b->[1]  # Vorname
    21:                    } @LoL;
    22:			
    23:  for $i ( 0 .. $#sortetLoL ) {
    24:      for $j ( 0 .. $#{$sortetLoL[$i]} ) {
    25:          print "$sortetLoL[$i]->[$j]\t\t";
    26:      }
    27:  	print "\n"
    28:  }
    

Interessant ist hier das Sortieren in den Zeilen 18 bis 21.  $a  und  $b  sind eigentlich Referenzen auf das zu sortierende Array. Damit ist  $a->[0]  eine Referenz auf des erste Element einer Zeile in der Liste von Listen.

    Feuerstein      Fred        fred@irgendwo.com		
    Feuerstein      Wilma       wilma@irgendwo.com		
    Geröllheimer    Barney      barney@irgendwo.anders.com		
    Geröllheimer    Betty       betty@irgendwo.anders.com		
    

Literaturhinweise:

Zurück zum Anfang dieses Projekts.