Dies ist der Befehl perllol, der beim kostenlosen Hosting-Anbieter OnWorks mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, dem Windows-Online-Emulator oder dem MAC OS-Online-Emulator ausgeführt werden kann
PROGRAMM:
NAME/FUNKTION
perllol – Manipulieren von Arrays von Arrays in Perl
BESCHREIBUNG
Erklärung und Zugriff of Arrays of Arrays
Die einfachste zweistufige Datenstruktur, die in Perl erstellt werden kann, ist manchmal ein Array aus Arrays
salopp als Liste von Listen bezeichnet. Es ist einigermaßen leicht zu verstehen, und zwar fast
Alles, was hier gilt, gilt später auch für die schickeren Daten
Strukturen.
Ein Array eines Arrays ist nur ein normales altes Array @AoA, das Sie mit zwei erreichen können
Indizes, wie $AoA[3][2]. Hier ist eine Deklaration des Arrays:
verwenden Sie 5.010; # damit wir say() verwenden können
# Weisen Sie unserem Array ein Array von Array-Referenzen zu
@AoA = (
[ "Fred", "Barney", "Kiesel", "Bambam", "Dino", ],
[ "george", "jane", "elroy", "judy", ],
[ "homer", "bart", "marge", "maggie", ],
);
sagen Sie $AoA[2][1];
bart
Nun sollte man sehr darauf achten, dass der äußere Klammertyp ein runder Typ ist, also ein
Klammer. Das liegt daran, dass Sie einem @-Array zuweisen und daher Klammern benötigen. Wenn
Du wolltest dort nicht ein @AoA zu sein, sondern nur ein Verweis darauf, könnte man tun
etwas eher so:
# Weisen Sie einem Array von Array-Referenzen eine Referenz zu
$ref_to_AoA = [
[ "Fred", "Barney", "Kiesel", "Bambam", "Dino", ],
[ "george", "jane", "elroy", "judy", ],
[ "homer", "bart", "marge", "maggie", ],
];
say $ref_to_AoA->[2][1];
bart
Beachten Sie, dass sich der Typ der äußeren Klammer geändert hat und sich daher auch unsere Zugriffssyntax geändert hat.
Das liegt daran, dass Sie in Perl im Gegensatz zu C Arrays und Referenzen nicht frei austauschen können
dazu. $ref_to_AoA ist eine Referenz auf ein Array, während @AoA ein eigentliches Array ist.
Ebenso ist $AoA[2] kein Array, sondern eine Array-Referenz. Wie kommt es also, dass Sie Folgendes schreiben können:
$AoA[2][2]
$ref_to_AoA->[2][2]
anstatt diese schreiben zu müssen:
$AoA[2]->[2]
$ref_to_AoA->[2]->[2]
Das liegt daran, dass die Regel lautet, dass nur bei benachbarten Klammern (ob quadratisch oder geschweift)
Es steht Ihnen frei, den Zeiger-Dereferenzierungspfeil wegzulassen. Aber Sie können dies nicht für immer tun
Das erste, wenn es sich um einen Skalar handelt, der eine Referenz enthält, was bedeutet, dass $ref_to_AoA immer gilt
braucht es.
persönlichem Wachstum Ihr Eigene
Das ist alles schön und gut für die Deklaration einer festen Datenstruktur, aber was wäre, wenn Sie es wollten?
spontan neue Elemente hinzufügen oder komplett neu aufbauen?
Schauen wir uns zunächst das Einlesen aus einer Datei an. Das ist so etwas wie das Hinzufügen einer Zeile bei a
Zeit. Wir gehen davon aus, dass es eine flache Datei gibt, in der jede Zeile eine Zeile und jedes Wort ein ist
Element. Wenn Sie versuchen, ein @AoA-Array zu entwickeln, das all dies enthält, finden Sie hier das Richtige
So geht das:
während (<>) {
@tmp = teilen;
push @AoA, [ @tmp ];
}
Möglicherweise haben Sie das auch aus einer Funktion geladen:
für $i ( 1 .. 10 ) {
$AoA[$i] = [irgendeineFunktion($i)];
}
Oder Sie hatten möglicherweise eine temporäre Variable mit dem Array darin herumliegen.
für $i ( 1 .. 10 ) {
@tmp = somefunc($i);
$AoA[$i] = [ @tmp ];
}
Es ist wichtig, dass Sie den Array-Referenzkonstruktor „[ ]“ verwenden. Das ist, weil
das würde nicht funktionieren:
$AoA[$i] = @tmp; # FALSCH!
Der Grund, warum das nicht das tut, was Sie wollen, liegt darin, dass Sie a ein solches benanntes Array zuweisen
Skalar nimmt ein Array im Skalarkontext, was bedeutet, dass nur die Anzahl gezählt wird
Elemente in @tmp.
Wenn Sie unter „Strikte Verwendung“ arbeiten (und wenn nicht, warum in aller Welt tun Sie das nicht?),
Sie müssen einige Erklärungen hinzufügen, um es glücklich zu machen:
Verwenden Sie strenge;
mein(@AoA, @tmp);
während (<>) {
@tmp = teilen;
push @AoA, [ @tmp ];
}
Natürlich muss das temporäre Array überhaupt keinen Namen haben:
während (<>) {
drücke @AoA, [ split ];
}
Sie müssen es auch nicht verwenden drücken(). Sie könnten einfach eine direkte Zuweisung vornehmen, wenn Sie es wüssten
wo du es hinstellen wolltest:
mein (@AoA, $i, $line);
für $i ( 0 .. 10 ) {
$line = <>;
$AoA[$i] = [ split " ", $line ];
}
oder auch nur
mein (@AoA, $i);
für $i ( 0 .. 10 ) {
$AoA[$i] = [ split " ", <> ];
}
Generell sollten Sie davor zurückschrecken, Funktionen zu verwenden, die möglicherweise Listen zurückgeben könnten
Skalarkontext ohne explizite Angabe. Dies wäre für den Laien klarer
Leser:
mein (@AoA, $i);
für $i ( 0 .. 10 ) {
$AoA[$i] = [ split " ", scalar(<>) ];
}
Wenn Sie eine $ref_to_AoA-Variable als Referenz auf ein Array haben möchten, müssen Sie dies tun
etwas wie das:
während (<>) {
push @$ref_to_AoA, [ split ];
}
Jetzt können Sie neue Zeilen hinzufügen. Wie wäre es mit dem Hinzufügen neuer Spalten? Wenn Sie es gerade zu tun haben
Bei Matrizen ist es oft am einfachsten, eine einfache Zuweisung zu verwenden:
für $x (1 .. 10) {
für $y (1 .. 10) {
$AoA[$x][$y] = func($x, $y);
}
}
für $x ( 3, 7, 9 ) {
$AoA[$x][20] += func2($x);
}
Es spielt keine Rolle, ob diese Elemente bereits vorhanden sind oder nicht: Es wird gerne erstellt
sie für Sie, indem Sie dazwischenliegende Elemente nach Bedarf auf „undef“ setzen.
Wenn Sie nur an eine Zeile anhängen wollten, müssten Sie etwas tun, das etwas lustiger aussieht:
# neue Spalten zu einer vorhandenen Zeile hinzufügen
push @{ $AoA[0] }, "wilma", "betty"; # expliziter Deref
Vor Perl 5.14 konnte dies nicht einmal kompiliert werden:
push $AoA[0], „wilma“, „betty“; # impliziter Deref
Wie kommts? Denn es war einmal, das Argument dazu drücken() musste ein echtes Array sein, nicht
nur ein Hinweis auf einen. Das stimmt nicht mehr. Tatsächlich ist die Zeile mit der Aufschrift „implicit deref“ gekennzeichnet.
Das obige funktioniert in diesem Fall einwandfrei, um das zu tun, was der explizite Deref-Befehl getan hat.
Der Grund, warum ich „in diesem Fall“ gesagt habe, ist dieser einzige funktioniert, weil $AoA[0] schon
hielt eine Array-Referenz. Wenn Sie das mit einer undefinierten Variablen versuchen, erhalten Sie eine
Ausnahme. Das liegt daran, dass die implizite Dereferenzierung niemals ein Undefiniertes automatisch belebt
Variable so, wie „@{ }“ immer funktioniert:
mein $aref = undef;
push $aref, qw(einige weitere Werte); # FALSCH!
push @$aref, qw(noch ein paar); # OK
Wenn Sie dieses neue implizite Dereferenzierungsverhalten nutzen möchten, gehen Sie wie folgt vor:
Es schont das Auge und das Handgelenk beim Programmieren. Verstehen Sie einfach, dass ältere Versionen ersticken werden
darauf während der Kompilierung. Immer wenn Sie etwas verwenden, das nur bei einigen funktioniert
Bei der Veröffentlichung von Perl und später, aber nicht früher, sollten Sie eine prominente Stelle platzieren
verwenden Sie v5.14; # wird für die implizite Deref von Array-Referenzen durch Array-Operationen benötigt
Anweisung oben in der Datei, die sie benötigt. Auf diese Weise, wenn jemand versucht, das auszuführen
neuen Code unter einem alten Perl, anstatt einen Fehler wie zu erhalten
Der Typ des zu übertragenden Arguments 1 muss ein Array (kein Array-Element) in /tmp/a Zeile 8, in der Nähe von „betty“; sein.
Die Ausführung von /tmp/a wurde aufgrund von Kompilierungsfehlern abgebrochen.
Das wird man ihnen höflich mitteilen
Perl v5.14.0 erforderlich – dies ist nur v5.12.3, gestoppt bei /tmp/a Zeile 1.
BEGIN fehlgeschlagen – Kompilierung in /tmp/a Zeile 1 abgebrochen.
Zugriff und Veredlung
Jetzt ist es an der Zeit, Ihre Datenstruktur auszudrucken. Wie wirst du das machen? Gut, wenn
Sie wollen nur eines der Elemente, es ist trivial:
drucke $AoA[0][0];
Ob Sie das Ganze ausdrucken wollen, können Sie allerdings nicht sagen
print @AoA; # FALSCH
weil Sie nur Referenzen aufgelistet bekommen und Perl niemals automatisch dereferenziert
Dinge für dich. Stattdessen müssen Sie sich selbst ein oder zwei Schleifen drehen. Dies druckt das Ganze
Struktur im Shell-Stil für() Konstrukt, um die äußere Menge von zu durchlaufen
Indizes.
für $aref ( @AoA ) {
sagen Sie „\t [ @$aref ],“;
}
Wenn Sie den Überblick über Indizes behalten möchten, können Sie Folgendes tun:
für $i ( 0 .. $#AoA ) {
say „\t elt $i is [ @{$AoA[$i]} ],“;
}
oder vielleicht sogar das. Beachten Sie die innere Schleife.
für $i ( 0 .. $#AoA ) {
für $j ( 0 .. $#{$AoA[$i]} ) {
say „elt $i $j ist $AoA[$i][$j]“;
}
}
Wie Sie sehen, wird es etwas kompliziert. Deshalb ist es manchmal einfacher, eine zu nehmen
vorübergehend auf dem Weg durch:
für $i ( 0 .. $#AoA ) {
$aref = $AoA[$i];
für $j ( 0 .. $#{$aref} ) {
say „elt $i $j ist $AoA[$i][$j]“;
}
}
Hmm... das ist immer noch ein bisschen hässlich. Wie wäre es damit:
für $i ( 0 .. $#AoA ) {
$aref = $AoA[$i];
$n = @$aref - 1;
für $j ( 0 .. $n ) {
say „elt $i $j ist $AoA[$i][$j]“;
}
}
Wenn Sie es satt haben, einen benutzerdefinierten Ausdruck für Ihre Datenstrukturen zu schreiben, könnten Sie einen Blick darauf werfen
die Standardmodule Dumpvalue oder Data::Dumper. Ersteres ist der Perl-Debugger
verwendet, während letzterer analysierbaren Perl-Code generiert. Zum Beispiel:
verwenden Sie v5.14; # unter Verwendung des +-Prototyps, neu in Version 5.14
Subshow(+) {
Dumpvalue erforderlich;
state $prettily = new Dumpvalue::
tick => q("),
compactDump => 1, # kommentiere diese beiden Zeilen aus
veryCompact => 1, # wenn Sie einen größeren Dump wünschen
;
dumpValue $prettily @_;
}
# Weisen Sie einem Array eine Liste von Array-Referenzen zu.
mein @AoA = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "homer", "marge", "bart" ],
);
push $AoA[0], „wilma“, „betty“;
zeige @AoA;
wird ausdrucken:
0 0..3 „fred“ „barney“ „wilma“ „betty“
1 0..2 „George“ „Jane“ „Elroy“
2 0..2 „homer“ „marge“ „bart“
Wenn Sie hingegen die beiden Zeilen auskommentieren, von denen ich gesagt habe, dass Sie sie vielleicht möchten, wird es Ihnen angezeigt
stattdessen auf diese Weise:
0 ARRAY(0x8031d0)
0 „Fred“
1 „Barney“
2 „Wilma“
3 „betty“
1 ARRAY(0x803d40)
0 „George“
1 „Jane“
2 „elroy“
2 ARRAY(0x803e10)
0 „Homer“
1 „Marge“
2 „Bart“
Scheiben
Wenn Sie an einen Slice (Teil einer Zeile) in einem mehrdimensionalen Array gelangen möchten, tun Sie dies
Ich muss ein paar ausgefallene Abonnements machen. Das liegt daran, dass wir zwar ein schönes Synonym dafür haben
Für die Dereferenzierung einzelner Elemente über den Zeigerpfeil besteht kein solcher Komfort
Scheiben.
Hier erfahren Sie, wie Sie eine Operation mithilfe einer Schleife ausführen. Wir gehen wie zuvor von einer @AoA-Variablen aus.
@part = ();
$ x = 4;
für ($y = 7; $y < 13; $y++) {
push @part, $AoA[$x][$y];
}
Dieselbe Schleife könnte durch eine Slice-Operation ersetzt werden:
@part = @{$AoA[4]}[7..12];
oder etwas weiter weg:
@part = @{ $AoA[4] } [ 7..12 ];
Aber wie Sie sich gut vorstellen können, kann das für den Leser ziemlich hart werden.
Ah, aber was wäre, wenn Sie eine wollten zweidimensional Scheibe, wie zum Beispiel, dass $x von 4..8 und $y läuft
von 7 auf 12 laufen? Hmm... hier ist der einfache Weg:
@newAoA = ();
for ($startx = $x = 4; $x <= 8; $x++) {
for ($starty = $y = 7; $y <= 12; $y++) {
$newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y];
}
}
Wir können einige Schleifen durch Slices reduzieren
für ($x = 4; $x <= 8; $x++) {
push @newAoA, [ @{ $AoA[$x] } [ 7..12 ] ];
}
Wenn Sie sich für Schwartz'sche Transformationen interessieren, hätten Sie dafür wahrscheinlich die Karte ausgewählt
@newAoA = map { [ @{ $AoA[$_] } [ 7..12 ] ] } 4 .. 8;
Allerdings würde Ihr Vorgesetzter Sie beschuldigen, dass Sie auf der Suche nach Arbeitsplatzsicherheit (oder schneller Unsicherheit) sind
Undurchschaubarer Code, darüber lässt sich kaum streiten. :-) Wenn ich du wäre, würde ich das in eins einfügen
Funktion:
@newAoA = splice_2D( \@AoA, 4 => 8, 7 => 12 );
sub splice_2D {
mein $lrr = Verschiebung; # ref auf Array von Array-Refs!
mein ($x_lo, $x_hi,
$y_lo, $y_hi) = @_;
Karte zurückgeben {
[ @{ $lrr->[$_] } [ $y_lo .. $y_hi ] ]
} $x_lo .. $x_hi;
}
Nutzen Sie Perllol online über die Dienste von onworks.net