2010-10-03 5 views
4

J'ai un tableau de hachages, tous avec le même jeu de clés, par exemple:Comment puis-je créer un hachage de hachages à partir d'un tableau de hachages en Perl?

my $aoa= [ 
{NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'}, 
{NAME=>'Susan', AGE=>36, SEX=>'F', ID=>, NATIONALITY=>'Swedish'}, 
{NAME=>'Bart', AGE=>120, SEX=>'M', ID=>987654, NATIONALITY=>'British'}, 
] 

Je voudrais écrire un sous-programme qui convertir en un hachage de hachages en utilisant une hiérarchie clé donnée:

my $key_hierarchy_a = ['SEX', 'NATIONALITY']; 
aoh_to_hoh ($aoa, $key_hierarchy_a) = @_; 
... 
} 

retournera

{M=> 
    {Swedish=>{{NAME=>'Dave', AGE=>12, ID=>123456}}, 
    British=>{{NAME=>'Bart', AGE=>120, ID=>987654}}}, 
F=> 
    {Swedish=>{{NAME=>'Susan', AGE=>36, ID=>}} 
} 

Notez cela crée non seulement la hiérarchie clé correcte mais également supprimer les clés maintenant redondantes.

Je suis coincé au point où j'ai besoin de créer le nouveau hachage le plus interne dans son emplacement hiérarchique correct.

Le problème est que je ne connais pas la "profondeur" (c'est-à-dire le nombre de touches). Si I a un nombre constant, que je pouvais faire quelque chose comme:

%h{$inner_hash{$PRIMARY_KEY}}{$inner_hash{$SECONDARY_KEY}}{...} = filter_copy($inner_hash,[$PRIMARY_KEY,$SECONDARY_KEY]) 

donc peut-être que je peux écrire une boucle qui ajoutera un niveau à la fois, retirez cette clé du hachage, que d'ajouter le hachage restant à la emplacement « en cours », mais il est un peu lourd et aussi je ne suis pas sûr de savoir comment garder un « lieu » dans un hachage de hachages ...

+2

Vous vous attendiez à une structure de données incorrecte. Par exemple, s'il y avait deux femelles suédoises, que devrait contenir '$ expected {FEMALE} {Swedish}'? La façon dont vous l'avez montré (hachage tout le long), il n'y a pas une bonne réponse à cette question. Mon hypothèse est que '$ expected {FEMALE} {Swedish}' doit être une ** référence de tableau contenant les références de hachage élaguées. – FMc

+0

@FM vous avez raison –

+0

Ceci n'est pas * difficile * à faire, mais vous devez lister une structure plus définie. Peut-être décrivant en XML la hiérarchie et quels sont les attributs/éléments qui se produisent une fois, et qui peuvent être listés plusieurs fois. – vol7ron

Répondre

6
use Data::Dumper; 

my $aoa= [ 
{NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'}, 
{NAME=>'Susan', AGE=>36, SEX=>'F', ID=>, NATIONALITY=>'Swedish'}, 
{NAME=>'Bart', AGE=>120, SEX=>'M', ID=>987654, NATIONALITY=>'British'}, 
]; 

sub aoh_to_hoh { 
    my ($aoa, $key_hierarchy_a) = @_; 
    my $result = {}; 
    my $last_key = $key_hierarchy_a->[-1]; 
    foreach my $orig_element (@$aoa) { 
    my $cur = $result; 
    # song and dance to clone an element 
    my %element = %$orig_element; 
    foreach my $key (@$key_hierarchy_a) { 
     my $value = delete $element{$key}; 
     if ($key eq $last_key) { 
     $cur->{$value} ||= []; 
     push @{$cur->{$value}}, \%element; 
     } else { 
     $cur->{$value} ||= {}; 
     $cur = $cur->{$value}; 
     } 
    } 
    } 
    return $result; 
} 

my $key_hierarchy_a = ['SEX', 'NATIONALITY']; 
print Dumper(aoh_to_hoh($aoa, $key_hierarchy_a)); 

Selon le commentaire de @ FM, vous voulez vraiment un supplément niveau de tableau là-bas.

La sortie:

$VAR1 = { 
      'F' => { 
        'Swedish' => [ 
            { 
            'ID' =>, 
            'NAME' => 'Susan', 
            'AGE' => 36 
            } 
           ] 
       }, 
      'M' => { 
        'British' => [ 
            { 
            'ID' => 987654, 
            'NAME' => 'Bart', 
            'AGE' => 120 
            } 
           ], 
        'Swedish' => [ 
            { 
            'ID' => 123456, 
            'NAME' => 'Dave', 
            'AGE' => 12 
            } 
           ] 
       } 
     }; 

EDIT: Oh, BTW - si quelqu'un sait comment le contenu élégant clone d'une référence, s'il vous plaît enseigner. Merci!

MODIFIER EDIT: @FM aidé. Tout mieux maintenant: D

+0

Doh, je suis un idiot. Je vais y remédier maintenant ...:) – Amadan

+0

Storable :: dclone peut être utilisé pour copier génériquement le contenu d'une structure de données profonde. – Ether

+0

@Ether: Merci pour cela! – Amadan

2

Comme vous l'avez expérimenté, écrire du code pour créer des structures de hachage d'une profondeur arbitraire est un peu délicat. Et le code pour accéder à de telles structures est tout aussi difficile. Ce qui fait une merveille: Voulez-vous vraiment faire cela?

Une approche plus simple pourrait consister à placer les informations d'origine dans une base de données. Tant que les clés qui vous intéressent sont indexées, le moteur DB pourra récupérer très rapidement les lignes qui vous intéressent: Donnez-moi toutes les personnes où SEX = femelle et NATIONALITE = suédois. Maintenant cela semble prometteur!

Vous pourriez également trouver ce loosely related question d'intérêt.

+0

Peut-être que vous avez raison. Je devrais jeter un oeil dans les bases de données dans Perl parfois. –

Questions connexes