Como posso imprimir o conteúdo de um hash no Perl?

167

Continuo imprimindo meu hash como # de baldes / # alocados. Como imprimo o conteúdo do meu hash?

Sem o uso de um whileloop seria o mais preferível (por exemplo, um one-liner seria o melhor).

Kys
fonte

Respostas:

253

Data :: Dumper é seu amigo.

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

irá produzir

$VAR1 = {
          'def' => [
                     4,
                     5,
                     6
                   ],
          'abc' => 123
        };
tetromino
fonte
3
o cartaz original também pode querer olhar para as várias opções Data :: Dumper, em particular de viragem na 'SORTKEYS' pode ser muito útil
plusplus
1
@ JonathanDay Estava faltando esse detalhe e foi útil! Obrigado!
Sos
5
O que significa adicionar uma barra na frente do%?
Shampoo
16
O operador @shampoo slash cria uma referência, um pouco como o &operador em C e C ++. A razão pela qual isso importa nesse contexto é que, em Perl, se você chamar uma função com um valor de hash como argumento, esse valor de hash será listado e expandido em vários argumentos - portanto, %hsh=("a" => 1, "b" => 2); foo(%hsh);seria equivalente a foo("a", 1, "b", 2). Se você em vez disso quer a função de operar no próprio haxixe, você precisa passar uma referência para o hash: foo(\%hsh);Veja perldoc.perl.org/perlsub.html#Pass-by-Reference
tetromino
63

Fácil:

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

Elegante, mas na verdade 30% mais lento (!):

while (my ($k,$v)=each %h){print "$k $v\n"}
Jonathan Graehl
fonte
9
Sleazy: print "@_ \ n", enquanto @_ = cada% h
FMc
Eu acho que você quer dizer print "$_ $h{$_}\n" for (keys %h);, $knão existe nesse exemplo.
Chas. Owens
4
Além disso, faça um benchmark antes de fazer reivindicações sobre eficiência (ou pelo menos qualificar o tipo de eficiência que você está falando). O forloop é mais rápido que as whileaté 10.000 chaves: gist.github.com/151792
Chas. Owens
1
Claro que você está certo: $ k. Mas é mais eficiente no Perl 6! :) Sim, você também está certo. Eu nunca teria pensado em otimizar ou criar um perfil no meu Perl, mas fico feliz em aprender isso. Obviamente, cada um deve ser mais eficiente (porque não há pesquisa de hash extra na chave). Mas é ~ 30% mais lento!
11138 Jonathan Graehl
Olá, Jonathan Graehl. Desculpe, ainda não entendi. Você está dizendo que cada um é ~ 30% mais lento com base no quê? É sempre, para todas as situações, uma diferença de 30%?
Carlos Sá
37

Aqui, como você pode imprimir sem usar Data::Dumper

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

Para fins de depuração, usarei frequentemente YAML.

use strict;
use warnings;

use YAML;

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

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

Resulta em:

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

Outras vezes eu usarei Data::Dump. Você não precisa definir tantas variáveis ​​para que ele a produza em um formato agradável do que o necessário Data::Dumper.

use Data::Dump = 'dump';

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

Mais recentemente, tenho usado Data::Printerpara depuração.

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

(O resultado pode ser muito mais colorido em um terminal)

Ao contrário dos outros exemplos que mostrei aqui, este foi projetado explicitamente para ser apenas para fins de exibição. O que aparece mais facilmente se você despejar a estrutura de uma variável vinculada ou a de um objeto.

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
fonte
ter as cores é "legal", mas estou fazendo algo errado ou usando "use Data :: Printer; p% var;" não imprime as setas em hashes, e para um novato como eu que ajuda
Sos
@Sosi Se você olhar para a saída na resposta, verá que ela não sai da maneira =>esperada. Em vez disso, sempre imprime a chave, vários espaços e, em seguida, o valor. O que ajuda uma varredura humana sobre a saída.
Brad Gilbert
12

A resposta depende do que está no seu hash. Se você tem um hash simples, um simples

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

ou

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

funcionará, mas se você tiver um hash preenchido com referências, terá algo que poderá percorrer essas referências e produzir uma saída sensata. Essa caminhada das referências é normalmente chamada de serialização. Existem muitos módulos que implementam estilos diferentes, alguns dos mais populares são:

Devido ao fato de fazer Data::Dumperparte da biblioteca principal do Perl, é provavelmente o mais popular; no entanto, alguns dos outros módulos têm coisas muito boas a oferecer.

Chas. Owens
fonte
10

Meu favorito: Smart :: Comentários

use Smart::Comments;
# ...

### %hash

É isso aí.

Axeman
fonte
5
Desculpe, voto negativo de mim para coisas que sequestram comentários para funcionalidade real. Um programador de manutenção poderia passar o dia todo tentando descobrir por que códigos como esse estavam imprimindo coisas inesperadas.
MikeKulls
2
@MikeKulls, np. É um filtro de origem, pelo que entendi. Além disso, tendo scripts escritos que verificam todos os módulos que coloco na preparação da produção, não use Smart::Commentsvejo isso também. Mas, para o contador, Smart::Commentsé muito bem comportado como um módulo com escopo , não deve haver comportamento de saída em nenhum módulo que também não use o SC. Portanto, o problema seria isolado para esses escopos com uma declaração de uso . Se você está dizendo que um programador de manutenção não tem responsabilidade de ler o documento nos módulos incluídos, não posso concordar. Ainda assim, obrigado por comentar
Axeman
7
Não estou dizendo que eles não têm responsabilidade, mas provavelmente não é a primeira coisa que procuram. Como nunca vi o módulo Smart Comments antes, eu não sabia por que o código acima estava imprimindo algo. Eu poderia passar dias pulando o comentário e nem processá-lo porque os comentários não deveriam fazer nada. Fazer eles fazerem algo é muito ruim. Eles podem ser usados ​​para gerar documentação, etc, desde que não alterem o comportamento do programa.
MikeKulls
4

Looping:

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

Funcional

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

Mas, por pura elegância, eu teria que escolher o wrang-wrang. Para o meu próprio código, eu escolheria meu foreach. Ou o uso de Dumper da tetro.

Paul Nathan
fonte
3
Não há diferença funcional entre seus usos de foreache map. mapdeve ser usado para a lista de transformações, não no contexto vazio para emular um loop for
Friedo
seria interessante ver os resultados do 'código de bytes' de cada um ... Gostaria de saber se o mapa é mais ou menos eficiente.
Ape-inago 22/07/2009
2

A maneira mais fácil em minhas experiências é apenas usar o Dumpvalue .

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

Funciona como um encanto e você não precisa se preocupar em formatar o hash, pois ele o gera como o depurador Perl (ótimo para depuração). Além disso, o Dumpvalue está incluído no conjunto de módulos Perl, para que você não precise mexer no CPAN se estiver atrás de algum tipo de proxy draconiano (como eu estou no trabalho).

Weegee
fonte
1

Se você quer ser pedante e mantê-lo em uma linha (sem as instruções de uso e o shebang), então eu meio que recuo da resposta do tetromino e sugiro:

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

Não fazer nada de especial além de usar o hash anônimo para pular a variável temp;)

Kyle Walsh
fonte
O OP diz que ele tem "meu hash" que precisa ser impresso. Essa resposta é apenas esperteza para seu próprio bem
justintime
A OP esperava fazer isso em uma linha. Estava apenas mostrando uma maneira de fazer uma linha. Então isso é digno de um voto negativo?
Kyle Walsh
1

Anexo um espaço para cada elemento do hash para vê-lo bem:

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

Eu realmente gosto de classificar as chaves em um código de linha:

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