Как я могу создать хэш хэшей из массива хэшей в Perl? - PullRequest
4 голосов
/ 03 октября 2010

У меня есть массив хэшей, все с одним и тем же набором ключей, например ::100100

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

Я хотел бы написать подпрограмму, которая преобразует это в хэш хэшей, используя данную иерархию ключей:

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

вернется

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

Обратите внимание, что это не только создает правильную иерархию ключей, но и удаляет избыточные ключи.

Я застреваю в точке, где мне нужно создать новый, самый внутренний хэш в правильном иерархическом расположении.

Проблема в том, что я не знаю "глубину" (то есть количество клавиш). Если у меня есть постоянное число, я мог бы сделать что-то вроде:

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

так что, возможно, я смогу написать цикл, который будет добавлять по одному уровню за раз, удалять этот ключ из хеша, а затем добавлять оставшийся хеш к «текущему» местоположению, но это немного громоздко, а также я не уверен как сохранить 'местоположение' в хэше хешей ...

Ответы [ 2 ]

6 голосов
/ 03 октября 2010
use Data::Dumper;

my $aoa= [
 {NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'},
 {NAME=>'Susan', AGE=>36, SEX=>'F', ID=>543210, 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));

Согласно комментарию @ FM, вам действительно нужен дополнительный уровень массива.

Выход:

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

РЕДАКТИРОВАТЬ: О, кстати - если кто-нибудь знает, как элегантно клонировать содержание ссылки, пожалуйста, научите Спасибо!

РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ: @FM помог. Все лучше сейчас: D

2 голосов
/ 03 октября 2010

Как вы уже знаете, написание кода для создания хеш-структур произвольной глубины немного сложнее.И код для доступа к таким структурам одинаково сложен.Что заставляет задуматься: Вы действительно хотите это сделать?

Более простой подход может заключаться в том, чтобы поместить исходную информацию в базу данных.Пока ключи, о которых вы заботитесь, проиндексированы, механизм DB сможет очень быстро получать интересующие строки: Дайте мне всех людей, где SEX = женский и NATIONALITY = шведский .Теперь это звучит многообещающе!

Вы также можете найти этот слабо связанный вопрос , представляющий интерес.

...