Variablen - %Hashes - HPK

Werbung
(C)2009, Kiermaier
Variablen - %Hashes
Was ist ein Hash? 'Assoziative Arrays'
Hashes sind array-ähnliche Datenstrukturen, die aus Schlüssel-Wert Paaren
bestehen.
Artikel + Preis
Apfel
Banane
Ananas
Birne
%Artikel =
Apfel
0,45
0,75
1,49
0,59
0,45
Banane 0,75
Ananas 1,49
Birne
0,59
Schlüssel
Skalarer Wert
(key)
(value)
64
Vom Prinzip her sind sich ein Array und ein Hash relativ ähnlich. Bei beiden
handelt es sich um eine Gruppe von Daten, bei der einzelne skalare Elemente
über einen Index ausgewählt werden. Allerdings sind bei Hashes diese Indizes in
der Regel keine Zahlenwerte, sondern statt dessen beliebige Strings bzw.
Skalare. Diese Strings bzw. Skalare werden Schlüssel oder Keys genannt.
Die Elemente (Values) eines Hashes sind wegen der fehlenden Indizes auch
nicht besonders geordnet, wie bei Arrays üblich. Im Gegenteil ist die Reihenfolge
der einzelnen Werte sogar völlig unerheblich, weil sie auf Grund der Schlüssel
leicht gefunden werden können. Wenn man neue Werte hinzufügt, wird einfach
ein neuer Hashwert angehängt. Die Perl-interne Suche nach einem
dazugehörigen Wert ist über einen Schlüsselstring natürlich langsamer als über
einen numerischen Index.
64
(C)2009, Kiermaier
Variablen - %Hashes
Wie erzeuge ich einen Hash?
Wie eine Liste (assoziative Liste):
%Artikel = ("Apfel", 0.45, "Banane", 0.75, "Ananas", 1.49, "Birne", 0.59);
Mit dem Doppelpfeil-Operator (comma arrow):
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
oder als einzelne skalare Werte:
erzeugt in anderer Reihenfolge den Hash:
$Artikel{'Apfel'} = 0.45;
$Artikel{'Banane'} = 0.75;
$Artikel{'Ananas'} = 1.49;
%Artikel =
$Preis = 0.59;
$Artikel{'Birne'} = $Preis;
Ananas 1,49
Banane 0,75
Apfel
0,45
Birne
0,59
65
Prinzipiell kann ein assoziatives Array (also ein Hash) genauso erzeugt werden,
wie eine 'normales' Array. Also schreibt man einfach, durch Kommas getrennt,
abwechselnd Schlüssel und dazugehörige Werte in eine Liste.
Deutlicher ist vielleicht die Schreibweise mit dem Pfeil-Operator. Dabei stehen
zwischen dem Schlüssel und dem dazugehörigen Wert die Zeichen '=>'.
Während man bei Arrays Barewords vermeiden sollte, sind hier die Anführungsstriche nicht in jedem Falle nötig. Durch den Pfeil-Operator wird der Schlüssel
ohnehin nicht interpretiert oder berechnet.
Da auch ein Hash aus einzelnen skalaren Datenwerten besteht, kann man ihn
auch in der Skalar-Schreibweise mit dem Schlüssel in geschweiften Klammern
definieren. Beachten Sie dabei, dass die Schlüssel dabei in Hochkommas stehen
(Barewords vermeiden!)!
In allen Fällen ist zu beachten, dass die Reihenfolge, in der Sie einen Hash
definieren, nicht von Perl eingehalten wird!
Die Schlüssel dürfen selbstverständlich nicht nur aus Zeichenketten sondern
auch aus Zahlen bestehen, was zum Teil verwirrend einem Array gleichen kann:
%PLZ = (0, 84036, 1, 84028, 2, 84032);
Dies ergibt einen Hash, der als 'Index' die Zahlen 0 bis 2 hat. Gespeichert wird
jedoch: 1=>84029, 0=>84036, 2=>84032.
Um einen Hash mit Variablenzwang (use strict) zu deklarieren, schreiben Sie
einfach my %hash = ();
Also wie bei einem Array wird zum Deklarieren einfach eine leere Liste
zugewiesen.
65
(C)2009, Kiermaier
Variablen - %Hashes
Wie benutzt man einen Hash?
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
print %Artikel, "\n";
Interpolation geht nicht!
print "%Artikel\n";
Statt dessen Zuweisung in ein Array und dessen Ausgabe mit Trennzeichen:
$" = ", ";
@rray = %Artikel;
print "@rray\n";
Einzelne Werte ausgeben (auch mit Interpolation):
print $Artikel{'Apfel'},"\n";
print "$Artikel{'Birne'}\n";
66
Um einen Hash auszugeben, sollte man beachten, dass ein Hash in Anführungszeichen nicht interpoliert wird. Mit der Print-Anweisung erscheint ein Hash
genauso wie ein Array. Will man die einzelnen Elemente mit Trennzeichen
ansehen, ist es praktisch, sie in ein Array zu übertragen und dann dieses
auszugeben.
Einzelne Hashwerte hingegen werden auch in Anführungsstrichen interpoliert und
ausgegeben.
Übung:
Schreiben Sie ein Programm, dass eine oder mehrere Textzeilen einliest und mit einer Leerzeile
beendet wird. Zerlegen Sie den Text in einzelne Worte und zählen dann, wie oft jedes Wort
vorkam. Benutzen Sie dazu einen Hash und die Worte als Schlüssel. Geben Sie am Schluss den
Hash aus.
Lösung:
66
(C)2009, Kiermaier
Variablen - %Hashes
Wie verändert man einen Hash?
Einen einzelnen Hash-Eintrag löschen:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
delete $Artikel{'Ananas'};
print %Artikel, "\n";
Mehrere Hash-Einträge (Slices) löschen:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
delete @Artikel{'Ananas', 'Banane'};
print %Artikel, "\n";
67
Ein einzelner Hash-Eintrag wird einfach über seinen Schlüssel gelöscht. Da es
ein einzelner Eintrag ist verwendet man das Skalarzeichen (= Einzelwert) und die
geschweifte Klammer mit dem Schlüssel, welche es als Hash kennzeichnet.
Mehrere Hashes sind ja nichts anderes als eine Liste. Deshalb werden Slices so
gelöscht, dass man das Arrayzeichen (= Werteliste) verwendet. Dahinter steht in
geschweiften Klammern eine Liste der Schlüssel, deren Hash-Eintrag gelöscht
werden soll.
Wollen Sie gleich den ganzen Hash löschen, weisen Sie ihm einfach wieder eine
leere Liste zu: %Hash = ( );
67
(C)2009, Kiermaier
Variablen - %Hashes
Hashfunktionen: mit Keys die Schlüssel finden
@Liste = keys(%Hash)
Beispiel:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
@Liste = keys(%Artikel);
print "@liste\n";
Beispiel mit sortierter Liste:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
@Liste = sort (keys(%Artikel));
print "@liste\n";
68
Die Funktion keys(%hash) erzeugt eine Liste aller Schlüssel im Hash. Anders
ausgedrückt liefert diese Funktion alle ungeraden Elemente (das erste, das dritte,
fünfte, etc.) der Hash-Liste zurück.
Da man in der Regel nicht weiß, in welcher Reihenfolge die Hash-Elemente
gespeichert sind, kann man mit Sort die Schlüssel sortieren.
Im skalaren Kontext liefert keys die Anzahl der Elemente im Hash zurück, z.B.
$n = keys(%hash).
Übung:
Schreiben Sie ein Programm, dass einzelne Wörter einliest bis man Strg+Z drückt (Einlesen je
Zeile in ein Array). Dann zählt es, wie oft jedes Wort vorkam. Geben Sie die alphabetisch
sortierten eingegebenen Wörter und die Häufigkeit nebeneinander aus.
Lösung:
68
(C)2009, Kiermaier
Variablen - %Hashes
Hashfunktionen: mit Values die Werte finden
@Liste = values(%Hash)
Beispiel:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
@Liste = values(%Artikel);
print "@liste\n";
Beispiel mit numerisch sortierter Liste:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
@Liste = sort {$a <=> $b} (values(%Artikel));
print "@liste\n";
69
Das Gegenteil zu keys ist die Funktion values. Sie liefert die Hash-Werte zurück,
also alle geraden Elemente einer Liste.
Übung:
Schreiben Sie das vorherige Programmm (zur keys-Funktion) so um, dass eine Rangfolge der
Wort-Häufigkeit entsteht. Also das häufigste Wort an erster Stelle und das seltenste an letzter
Stelle.
Lösung:
69
(C)2009, Kiermaier
Kontrollstrukturen
Endlosschleifen mit While und Until
Schleife ausführen, solange (Vergleich) zutrifft, also wahr ist:
while (Vergleich) {Anweisungsblock}
Schleife ausführen, solange (Vergleich) nicht zutrifft, also falsch ist:
until (Vergleich) {Anweisungsblock}
Beispiel zu while:
print "Wie alt bist du?";
chomp($alt = <stdin>);
while ($alt > 0) {
print "Du warst mal $alt Jahre alt.\n";
$alt--;
}
Beispiel zu until:
print "Wie alt bist du?";
chomp($alt = <stdin>);
until ($alt == 0) {
print "Du warst mal $alt Jahre alt.\n";
$alt--;
}
70
Neben den Schleifenkonstruktionen mit For und ForEach gibt es in Perl auch
andere Konstruktionen, die praktisch anwendbar sind. Während For meist mit
einer Schleifenvariable eine begrenzte Anzahl von Durchläufen benutzt, werden
die Anweisungen While und Until für Endlosschleifen benutzt. Die Abbruchbedingung ergibt sich aus einem Vergleich, der wahr oder falsch sein kann.
Die While-Schleife wird solange durchlaufen, solange ein Vergleich den Wert
wahr (=1) ergibt. Die Anweisung while (1) ergibt also eine Endlosschleife, die nur
mit Last wieder verlassen werden kann (die Bedingung ist immer erfüllt).
Die Until-Schleife reagiert genau anders herum: sie wird durchlaufen, solange ein
Vergleich den Wert falsch ergibt. Also solange, bis der Vergleich wahr wird.
Demzufolge stellt die Anweisung until (0) ebenso eine Endlosschleife.
Gerne benutzt wird auch die folgende Anweisung
Do {
Anweisungsblock
} while (Vergleich);
Das ist immer dann interessant, wenn der Anweisungsblock wenigstens einmal
durchlaufen werden soll. While bzw. Until statt do würde statt dessen den
Anweisungsblock sofort überspringen, wenn der Vergleich erfüllt ist.
70
(C)2009, Kiermaier
Variablen - %Hashes
Hashfunktionen: mit each Schlüssel/Wertpaare finden
@Eintrag = each(%Hash)
($Schlüssel, $Wert) = each(%Hash)
Beispiel:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
foreach (keys (%Artikel)) {
($key, $Wert) = each (%Artikel);
print "$key\t $Wert\n";
}
Beispiel mit while-Schleife:
%Artikel = (Apfel => 0.45, Banane => 0.75, Ananas => 1.49, Birne => 0.59);
while (($key, $Wert) = each(%Artikel)) {
print "$key\t $Wert\n";
}
71
Mit der Funktion 'each' werden nacheinander alle Schlüssel/Wertpaare einer
Liste zugewiesen.
Die Each-Funktion liefert im skalaren Kontext eine 0 zurück, wenn keine
Schlüssel/Wertpaare mehr vorhanden sind. Deshalb eignet sich diese Funktion
besonders als Abbruchbedingung für While-Schleifen.
71
(C)2009, Kiermaier
Variablen - %Hashes
Mit Reverse die Schlüssel/Wertpaare vertauschen
%NeuHash = reverse (%Hash)
Beispiel:
%Internet = (Deutschland => de, Oesterreich => at, Schweiz => ch);
while (($land, $kurz) = each(%Internet)) {
print "$land hat Webkuerzel $kurz\n";
}
%Internet = reverse (%Internet);
#Schlüssel und Wert vertauschen
while (($kurz, $land) = each(%Internet)) {
print "Webkuerzel $kurz gehoert zu $land\n";
}
72
Mit der Reverse-Funktion lassen sich auch die Schlüssel/Wertpaare vertauschen.
Damit ist es möglich in einem Hash nach dem Wert oder nach dem Schlüssel zu
sortieren und zu suchen. Zu beachten ist dabei allerdings, dass die Zuordnung
eindeutig sein muss. Das heißt, wenn Werte doppelt vorkommen, sind
anschließend die ersten Einträge des Werts gelöscht!
Übung:
Schreiben Sie ein Programm, das als Überschrift ***Telefonliste anlegen*** ausgibt. Dann werden
solange Namen und anschließend Telefonnummern eingelesen, bis kein Name mehr eingegeben
wird. Die Paare werden in einem Hash gespeichert.
Nach zwei Leerzeilen steht die Überschrift 'Freundeliste'. Dann werden sortiert die Namen und
nach drei Tabulatoren die dazugehörigen Telefonummern ausgegeben.
Nach zwei weiteren Leerzeilen wird dann die Überschrift 'Telefonliste' und sortiert die
Telefonummern und nach drei Tabulatoren die dazugehörigen Namen ausgegeben.
Lösung:
72
(C)2009, Kiermaier
Variablen - %Hashes
Hash von Hashes
%Hash = ( %Hash1, %Hash2, …)
Beispiel:
%Tabelle = ( 'Zeile1' => {'U' => 10, 'I' => 0.01, 'R' => 0},
'Zeile2' => {'U' => 10, 'I' => 0.09, 'R' => 0});
foreach $zeile (keys %Tabelle) {
#zeilenweise auslesen
print "$zeile\n";
$u = $Tabelle{$zeile}{'U'};
#Element U aus $zeile
$i = $Tabelle{$zeile}{'I'};
#Element I aus $zeile
$Tabelle{$zeile}{'R'} = $Tabelle{$zeile}{'U'} / $Tabelle{$zeile}{'I'};
print "$u / $i = $Tabelle{$zeile}{'R'}\n";
foreach $key (keys %{$Tabelle{$zeile}}) { #alle Elemente der Zeile
print "$key = $Tabelle{$zeile}{$key}; "; #mit dem Schlüssel ausgeben
}
print "\n";
}
73
Wie schon bei den Arrays kann man auch Hashes verschachteln. Es gibt deshalb
auch Arrays von Hashes, Hashes von Arrays und Hashes von Hashes.
Während man bei zweidimensionalen Arrays auf ein Element mit den Indizes in
eckigen Klammern zugegriffen hat, erfolgt es beim Hash von Hashes über die
geschweiften Klammern. Bei den Mischformen sind dann auch die Klammern
gemischt (Es geht beliebig kompliziert, was man auch einfach machen könnte.
Siehe dazu besser andere Programmiersprachen).
73
(C)2009, Kiermaier
Variablen – Besondere Variablen
Systemvariablen
Der Hash für die Umgebungsvariablen heißt %ENV.
Beispiel (gibt die Windows-Umgebungsvariablen sortiert aus):
while (($var, $wert) = each(%ENV)) {
printf "%-24s = %-s\n", $var, $wert;
}
Beispiel (gibt Ihren Anmeldenamen und Computernamen aus):
print "Sie sind User $ENV{USERNAME}.\n";
print "Sie sitzen an dem $ENV{'OS'}-Rechner $ENV{'COMPUTERNAME'}.\n"
Das Array für die Aufrufparameter beim Start des Programms heißt @ARGV.
Beispiel (Aufruf z.B. mit perl addiere.pl 3 4 5):
if ($#ARGV == -1) {die "Aufruf mit Parameter \'zahl1 zahl2\'\n"}
foreach (@ARGV) {$erg += $_}
print "Summe = $erg\n";
74
Es gibt eine Menge Sondervariablen die bestimmte Inhalte präsentieren.
Die Umgebungsvariablen sind zum Beispiel in dem Hash %ENV gespeichert.
Dort können Sie mit $ENV{Schlüssel} abgefragt oder auch verändert werden,
allerdings nicht systemweit und dauerhaft.
Wenn man hinter einem Programm weitere Angaben setzt (=Aufrufparameter)
kann man diese im Array @ARGV ansehen. Wenn das Array leer ist, also nichts
übergeben wurde, steht der höchste Index auf -1.
Oft wird ein Aufrufparameter auch mit shift (ohne weitere Argumente) abgeholt.
Dann ist die Benutzung von @ARGV nicht nötig (aber leider etwas
undurchsichtig, woher der Wert kommt). Das sieht dann so aus:
$werte = shift;
@liste = split(/ /, $werte);
Wenn $werte leer ist, wurden keine Parameter übergeben.
74
(C)2009, Kiermaier
Variablen – Besondere Variablen
Systemzeit in ein Array lesen
@Datumzeit = localtime(time)
Beispiel:
use strict 'vars';
my ($Sekunden, $Minuten, $Stunden, $Monatstag, $Monat,
$Jahr, $Wochentag, $Jahrestag, $Sommerzeit) = localtime(time);
my %zeit = (Std => $Stunden, Min => $Minuten, Sek => $Sekunden);
my %datum = (Tag => $Monatstag, Mon => $Monat+1, Jhr => $Jahr+1900);
my @Wochentage =
("Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag");
#Formatierung: %02u => 0 mit Null auffüllen, 2 Stellen, u unsigned Integer
printf "Aktuelle Uhrzeit ist %02u:%02u:%02u.\n",
$zeit{Std}, $zeit{Min}, $zeit{Sek};
printf "Heute ist $Wochentage[$Wochentag], der %02u.%02u.%04u\n",
$datum{Tag}, $datum{Mon}, $datum{Jhr};
75
Die Funktion localtime(time) ermittelt eine Liste mit den aktuellen Zeitwerten des
Computers. Manche dieser Werte müssen noch etwas angepasst werden, weil
die Rückgabewerte mit 0 statt mit 1 beginnen. Dazu gehört der Monat und der
Jahrestag (der wievielte Tag des Jahres). Außerdem beginnen die Jahre erst bei
1900 mit dem Wert 0. Man muss also 1900 zur Jahreszahl addieren.
75
Herunterladen