2010-08-26 7 views
5

En supposant que j'ai un hachage comme ceci:Comment savoir si un hachage Perl est multidimensionnel?

$hash_ref = { 

    'hashes' => { 
    'h1' => { 'klf' => '1', 'moomooland' => '1' }, 
    'h2' => { 'klf' => '2', 'moomooland' => '2' }, 
    'h3' => { 'klf' => '3', 'moomooland' => '3' } 
    }, 

    'keys' => { 
    'k1' => 'key1', 
    'k2' => 'key2', 
    'k3' => 'key3' 
    } 

} 

Comment pourrais-je savoir, aussi facile que possible, que hashes contient 3 plus hash, tandis que keys contient 3 paires clé/valeur?

ref retournera HASH pour les deux, et je ne suis pas sûr s'il est possible de trouver peut-être la profondeur de ces hachages.

Merci :)

+0

Oui, c'est possible, mais je me demande pourquoi vous voudriez le savoir. Cela peut aider à décider d'un plan d'action approprié. par exemple. Voulez-vous retourner la chaîne la plus profonde, ou la profondeur de toutes les différentes branches? – Zaid

+2

Copie possible: [Traverser un hachage multidimensionnel en Perl] (http://stackoverflow.com/questions/160175/traversing-a-multi-dimensional-hash-in-perl) – Zaid

+0

Je devrais le savoir Je peux invoquer une action différente selon que j'obtiens 3 hachages ou 3 paires clé/valeur. Donc, je n'ai pas nécessairement besoin de connaître la profondeur exacte, si je peux différencier ces 2 d'une autre manière. Je vois votre lien vers une autre question maintenant, mais j'espérais que cela pourrait être fait sans utiliser la récursivité :) – sentinel

Répondre

5

Si vous avez juste besoin de savoir si un hachage est multidimensionnel, vous pouvez itérer sur ses valeurs et arrêter si une référence se trouve:

my $is_multi_dimensional = 0; 

for my $value (values %$hash_ref) { 
    if ('HASH' eq ref $value) { 
     $is_multi_dimensional = 1; 
     last; 
    } 
} 

ou vous pouvez utiliser la fonction each():

while (my (undef, $value) = each %$hash_ref) { 
    if ('HASH' eq ref $value) { 
     $is_multi_dimensional = 1; 
     last; 
    } 
} 
+0

Oh, c'est assez brillant. Si simple, mais si logique et efficace. Argh, pourquoi je n'y ai pas pensé? :) Merci Eugene, cela fonctionne parfaitement bien pour ce dont j'ai besoin, bien que maintenant je réalise que le libellé de ma question n'explique pas vraiment que c'est ce que je cherchais, plutôt que d'obtenir la profondeur exacte d'un hachage. Oups. – sentinel

+1

Etes-vous sûr que chaque() est plus efficace que values ​​()? Comme il utilise l'itérateur interne, il peut court-circuiter ce qui aide les hachages géants, mais il a l'inconvénient général d'utiliser l'itérateur de hachage (global!). each() est un défaut de fonctionnement, IMO. – tsee

+2

@tsee: il est plus efficace pour les hachages plus gros, car il ne crée pas une liste intermédiaire de valeurs. Et c'est la seule façon d'opter pour des hachages très gros (par exemple liés). Bien sûr, il faut se souvenir qu'il y a un seul itérateur pour chaque hachage dans le programme, par conception. –

1

Vous pouvez essayer celui-ci pour connaître la profondeur de hachage Perl:

#!/usr/bin/perl 
use strict; 
my $hash_ref = { 

    'hashes' => { 
    'h1' => { 'klf' => '1', 'moomooland' => '1' }, 
    'h2' => { 'klf' => '2', 'moomooland' => '2' }, 
    'h3' => { 'klf' => '3', 'moomooland' => '3' } 
    }, 

    'keys' => { 
    'k1' => 'key1', 
    'k2' => 'key2', 
    'k3' => 'key3' 
    } 

}; 
print_nested_hash($hash_ref, 0); 

sub print_nested_hash { 
    my $hash_ref = shift; 
    my $depth = shift; 
    foreach my $key (sort keys %{$hash_ref}) { 
     print ' ' x $depth, $key, "\n"; 

     if (ref($hash_ref->{$key}) eq "HASH") { 
      print_nested_hash($hash_ref->{$key}, $depth+1); 
     } 
    } 
} 

SORTIE:

hashes 
    h1 
     klf 
     moomooland 
    h2 
     klf 
     moomooland 
    h3 
     klf 
     moomooland 
keys 
    k1 
    k2 
    k3 
5

Vous pouvez également first et grep pour cela:

use List::Util 'first'; 
say 'is multi-dimensional' if first { ref } values %$hash_ref; 

# explicitly check for HASH ref this time 
my $how_many_md_hashes = grep { 'HASH' eq ref } values %$hash_ref; 

NB. first (partie du module de base List::Util) courts-circuits est donc idéal pour les conditions et est probablement le plus rapide de toutes les options possibles.

/I3az/

+2

Vous pouvez utiliser 'any' au lieu de 'first' si vous vous souciez uniquement de la véracité plutôt que de la valeur réelle qui correspond: 'use List :: MoreUtils 'any'; my $ is_multi_dimensional = toutes les valeurs {ref}% $ hash_ref; ' – Ether

Questions connexes