Wie kann ich den Inhalt eines Hash in Perl drucken?

167

Ich drucke meinen Hash weiterhin als Anzahl der zugewiesenen Eimer. Wie drucke ich den Inhalt meines Hash?

Ohne Verwendung einer whileSchleife wäre am meisten vorzuziehen (zum Beispiel wäre ein Einzeiler am besten).

Kys
quelle

Antworten:

253

Data :: Dumper ist dein Freund.

use Data::Dumper;
my %hash = ('abc' => 123, 'def' => [4,5,6]);
print Dumper(\%hash);

wird ausgegeben

$VAR1 = {
          'def' => [
                     4,
                     5,
                     6
                   ],
          'abc' => 123
        };
Tetromino
quelle
3
Das Originalposter möchte möglicherweise auch einen Blick auf die verschiedenen Data :: Dumper-Optionen werfen. Insbesondere das Aktivieren von 'Sortkeys' kann sehr nützlich sein
plusplus
1
@ JonathanDay Ich habe dieses Detail vermisst und es war hilfreich! Vielen Dank!
Sos
5
Was bedeutet es, einen Schrägstrich vor dem% einzufügen?
Shampoo
16
Der @ slampoo-Schrägstrichoperator erstellt eine Referenz, ähnlich dem &Operator in C und C ++. Der Grund, warum dies in diesem Zusammenhang wichtig ist, ist, dass in Perl, wenn Sie eine Funktion mit einem Hash-Wert als Argument aufrufen, dieser Hash-Wert aufgelistet und in mehrere Argumente erweitert wird - dies %hsh=("a" => 1, "b" => 2); foo(%hsh);entspricht alsofoo("a", 1, "b", 2) . Wenn Sie stattdessen die Funktion für den Betrieb auf dem Hash wollen selbst, müssen Sie einen Verweis auf die Hash weitergeben müssen: foo(\%hsh);Siehe perldoc.perl.org/perlsub.html#Pass-by-Reference
Tetromino
62

Einfach:

print "$_ $h{$_}\n" for (keys %h);

Elegant, aber tatsächlich 30% langsamer (!):

while (my ($k,$v)=each %h){print "$k $v\n"}
Jonathan Graehl
quelle
9
Sleazy: drucke "@_ \ n", während @_ = jeweils% h
FMc
Ich denke du meinst print "$_ $h{$_}\n" for (keys %h);, $kexistiert in diesem Beispiel nicht.
Chas. Owens
4
Vergleichen Sie auch, bevor Sie Aussagen zur Effizienz machen (oder qualifizieren Sie zumindest die Art der Effizienz, über die Sie sprechen). Die forSchleife ist schneller als die whilebis zu mindestens 10.000 Schlüssel: gist.github.com/151792
Chas. Owens
1
Natürlich hast du recht bezüglich: $ k. Aber in Perl 6 ist es effizienter! :) Ja, da hast du auch Recht. Ich hätte nie gedacht, mein Perl tatsächlich zu optimieren oder zu profilieren, aber ich bin froh, dies zu lernen. Natürlich jeder sollte effizienter sein (weil es kein zusätzlicher Hash - Lookup auf dem Schlüssel). Aber es ist ~ 30% langsamer!
Jonathan Graehl
Hallo Jonathan Graehl. Entschuldigung, immer noch nicht verständnisvoll. Sie sagen, dass jeder ~ 30% langsamer ist, basierend auf was? Ist jedes Mal für jede Situation eine Lücke von 30%?
Carlos Sá
37

Hier erfahren Sie, wie Sie ohne Verwendung drucken können Data::Dumper

print "@{[%hash]}";
Tim Diekmann
quelle
24

Zum Debuggen werde ich oft verwenden YAML.

use strict;
use warnings;

use YAML;

my %variable = ('abc' => 123, 'def' => [4,5,6]);

print "# %variable\n", Dump \%variable;

Ergebnisse in:

# %variable
---
abc: 123
def:
  - 4
  - 5
  - 6

Andere Male werde ich verwenden Data::Dump. Sie müssen nicht so viele Variablen festlegen, damit es in einem schönen Format ausgegeben wird, als Sie es tun Data::Dumper.

use Data::Dump = 'dump';

print dump(\%variable), "\n";
{ abc => 123, def => [4, 5, 6] }

In jüngerer Zeit habe ich Data::Printerzum Debuggen verwendet.

use Data::Printer;
p %variable;
{
    abc   123,
    def   [
        [0] 4,
        [1] 5,
        [2] 6
    ]
}

(Ergebnis kann auf einem Terminal viel bunter sein)

Im Gegensatz zu den anderen Beispielen, die ich hier gezeigt habe, dient dieses Beispiel explizit nur zur Anzeige. Dies wird leichter angezeigt, wenn Sie die Struktur einer gebundenen Variablen oder die eines Objekts ausgeben.

use strict;
use warnings;

use MTie::Hash;
use Data::Printer;

my $h = tie my %h, "Tie::StdHash";
@h{'a'..'d'}='A'..'D';
p %h;
print "\n";
p $h;
{
    a   "A",
    b   "B",
    c   "C",
    d   "D"
} (tied to Tie::StdHash)

Tie::StdHash  {
    public methods (9) : CLEAR, DELETE, EXISTS, FETCH, FIRSTKEY, NEXTKEY, SCALAR, STORE, TIEHASH
    private methods (0)
    internals: {
        a   "A",
        b   "B",
        c   "C",
        d   "D"
    }
}
Brad Gilbert
quelle
Die Farben zu haben ist "ordentlich", aber entweder mache ich etwas falsch oder benutze "use Data :: Printer; p% var;" druckt die Pfeile nicht in Hashes, und für einen Neuling wie mich hilft das
Sos
@Sosi Wenn Sie sich die Ausgabe in der Antwort ansehen, werden Sie feststellen, dass sie nicht =>wie erwartet ausgibt . Stattdessen wird immer der Schlüssel, mehrere Leerzeichen und dann der Wert gedruckt. Dies hilft einem Menschen, die Ausgabe zu scannen.
Brad Gilbert
12

Die Antwort hängt davon ab, was in Ihrem Hash enthalten ist. Wenn Sie einen einfachen Hash haben, einen einfachen

print map { "$_ $h{$_}\n" } keys %h;

oder

print "$_ $h{$_}\n" for keys %h;

wird tun, aber wenn Sie einen Hash haben, der mit Referenzen gefüllt ist, werden Sie etwas, das diese Referenzen durchlaufen und eine vernünftige Ausgabe erzeugen kann. Dieses Durchlaufen der Referenzen wird normalerweise als Serialisierung bezeichnet. Es gibt viele Module, die unterschiedliche Stile implementieren. Einige der beliebtesten sind:

Aufgrund der Tatsache, dass Data::Dumperes Teil der Perl-Kernbibliothek ist, ist es wahrscheinlich die beliebteste. Einige der anderen Module haben jedoch sehr gute Dinge zu bieten.

Chas. Owens
quelle
10

Mein Favorit: Smart :: Kommentare

use Smart::Comments;
# ...

### %hash

Das ist es.

Axeman
quelle
5
Entschuldigung, stimmen Sie von mir für Dinge ab, die Kommentare für die tatsächliche Funktionalität entführen. Ein Wartungsprogrammierer könnte den ganzen Tag damit verbringen, herauszufinden, warum Code wie dieser unerwartete Dinge druckt.
MikeKulls
2
@ MikeKulls, np. Es ist ein Quellfilter, also verstehe ich. Nachdem ich Skripte geschrieben habe, die jedes Modul überprüfen, das ich in die Produktionsvorbereitung eingefügt habe use Smart::Comments, sehe ich es auch aus dieser Perspektive. Aber an die Theke, Smart::Commentsist ziemlich gut als artig scoped Modul, sollte es nicht Ausgabeverhalten in jedem Modul sein , das nicht auch nicht verwenden SC. Das Problem würde also mit einer use- Anweisung auf diese Bereiche beschränkt . Wenn Sie sagen, dass ein Wartungsprogrammierer nicht dafür verantwortlich ist, das Dokument zu den enthaltenen Modulen zu lesen, kann ich dem nicht zustimmen. Trotzdem, danke für den Kommentar
Axeman
7
Ich sage nicht, dass sie keine Verantwortung haben, aber es ist wahrscheinlich nicht das erste, wonach sie suchen. Ich hatte noch nie ein Smart Comments-Modul gesehen, bevor ich nicht wusste, warum der obige Code etwas druckte. Ich könnte Tage damit verbringen, den Kommentar zu überspringen und ihn nicht einmal zu verarbeiten, da Kommentare nichts bewirken sollten. Sie dazu zu bringen, etwas zu tun, ist imo sehr schlecht. Sie können zum Generieren von Dokumentation usw. verwendet werden, solange sie das Verhalten des Programms nicht ändern.
MikeKulls
4

Looping:

foreach(keys %my_hash) { print "$_ / $my_hash{$_}\n"; }

Funktionell

map {print "$_ / $my_hash{$_}\n"; } keys %my_hash;

Aber für pure Eleganz müsste ich Wrang-Wrang wählen. Für meinen eigenen Code würde ich meinen foreach wählen. Oder Tetro Dumper verwenden.

Paul Nathan
quelle
3
Es gibt keinen funktionalen Unterschied zwischen Ihrer Verwendung von foreachund map. mapsollte für
Listentransformationen
Es wäre interessant, die Ergebnisse des 'Byte-Codes' von jedem zu sehen ... Ich frage mich, ob die Karte mehr oder weniger effizient ist.
Ape-inago
2

Nach meinen Erfahrungen ist es am einfachsten, nur Dumpvalue zu verwenden .

use Dumpvalue;
...
my %hash = { key => "value", foo => "bar" };
my $dumper = new DumpValue();
$dumper->dumpValue(\%hash);

Funktioniert wie ein Zauber und Sie müssen sich keine Gedanken über das Formatieren des Hashs machen, da er wie der Perl-Debugger ausgegeben wird (ideal zum Debuggen). Außerdem ist Dumpvalue im Standardsatz der Perl-Module enthalten, sodass Sie sich nicht mit CPAN herumschlagen müssen, wenn Sie sich hinter einem drakonischen Proxy befinden (wie ich bei der Arbeit bin).

Weegee
quelle
1

Wenn Sie pedantisch sein und es in einer Zeile halten möchten (ohne Use Statements und Shebang), dann werde ich mich von Tetrominos Antwort zurückziehen und vorschlagen:

print Dumper( { 'abc' => 123, 'def' => [4,5,6] } );

Ich mache nichts Besonderes als den anonymen Hash, um die temporäre Variable zu überspringen;)

Kyle Walsh
quelle
Das OP sagt, er hat "meinen Hash", der gedruckt werden muss. Diese Antwort ist nur Klugheit um ihrer selbst willen
justintime
OP hatte gehofft, es in einer Zeile zu tun. Zeigte nur eine einzeilige Vorgehensweise. Das ist also eine Abwertung wert?
Kyle Walsh
1

Ich füge jedem Element des Hash ein Leerzeichen hinzu, um es gut zu sehen:

print map {$_ . " "} %h, "\n";
carlos_lm
quelle
1

Ich mag es wirklich, die Schlüssel in einem Liner-Code zu sortieren:

print "$_ => $my_hash{$_}\n" for (sort keys %my_hash);
Labist
quelle