Сопоставление и слияние вложенных хэшей Perl

#arrays #perl #hash #reference

Вопрос:

У меня есть файл, который считывается и разделяется на %объектов, %объектов заполняются, как показано ниже.

 $VAR1 = 'cars';
$VAR2 = {
          'car1' => {
                        'info1' => '"fast"',
                        'info2' => 'boring'
                      },
          'car2' => {
                        'info1' => '"slow"',
                        'info2' => 'boring info'
                      },
          'car3' => {
                        'info1' => '"unique"',
                        'info2' => 'useless info'
                      }
                };
$VAR3 = 'age';
$VAR4 = {
          'new' => {
                                  'info3' => 'rust',
                                  'info4' => '"car1"'
                                },
          'old' => {
                                  'info3' => 'shiny',
                                  'info4' => '"car2" "car3"'
                                }
                   }
         };              
 

Моя цель состоит в том, чтобы вставить такие данные, как «car1 быстрая ржавчина, car2 медленный блеск, car3 уникальный блеск», в базу данных, но я не могу получить, например, «ржавчина соответствует возрасту на основе info4» ..

 my $key = cars;
my $key2 = age;

foreach my $obj (keys %{$objects{$key}}) {                          # for every car
    @info1s = $objects{$type}{$obj}{'info1'} =~ m/"(.*?)"/g;        # added to clean up all info1
    foreach my $infos ($info1s) {
        dbh execute insert $obj $infos                              # this gives me "car1 fast, car2 slow, car3 unique"
    } 
...
 

Может ли кто-нибудь, пожалуйста, указать мне правильное направление для получения и хранения информации 4 с соответствующей информацией 1/info2?

Спасибо!

Комментарии:

1. Как это связано-это потому info4 , что имеет значение car1 , которое является ключом во второй хэш-ссылке $VAR2 ? Похоже, вам просто нужно тщательно перебрать эти структуры данных. Кстати, пожалуйста, добавьте, какой из показанных дампов является структурой данных в коде. В коде есть только один ( %objects ), но дамп показывает несколько.

2. Да, именно так они соотносятся, и я изо всех сил пытаюсь понять, как им соответствовать. Пример кода должен давать вывод только из VAR1 и VAR2, поскольку я изо всех сил пытаюсь сопоставить и извлечь данные из остальных. Если я продолжу спускаться по петле (foreach), добавив еще один $obj2 с $key2, я просто получу беспорядок записей, например, каждая машина будет быстрой, медленной и уникальной и т.д..

3. Всегда ли это одни и те же метки, info1 сквозные info4 , в хэшрефе второго уровня? Или это просто две пары ключ-значение в нижней (самой глубокой) хэшрефе?

4. Это всегда одни и те же ярлыки, поэтому ответ принимается. Хороший трюк с данными::Лист::Ходок, чтобы получить самые глубокие значения. Я посмотрю, смогу ли я поиграть с этим, чтобы все это подходило, потрясающе!

Ответ №1:

Я полагаю, что цель состоит в следующем. Получите значения для info4 ключей () в $VAR4 хэш-ссылке самого глубокого уровня и найдите их как ключи верхнего уровня в $VAR2 хэш-ссылке. Затем свяжите с ними обоими значение из info3 ключа (), их «родного брата» в хэшрефе их собственного $VAR4 самого глубокого уровня, а также значение ключа ( info1 ) из $VAR2 .

Для этой цели можно обойти структуру вручную, особенно если она всегда имеет те же два уровня, что и показано на рисунке, но с библиотеками это проще и лучше. Я использую Data::Leaf::Walker для получения листьев (самых глубоких значений) и ключевых путей к ним, а Data::Diver-для получения значений для известных путей.

 use warnings;
use strict;
use feature 'say';
use Data::Dump;    
use Data::Leaf::Walker;
use Data::Diver qw(Dive);

my $hr1 = {
    'car1' => { 'info1' => 'fast',   'info2' => 'boring' },
    'car2' => { 'info1' => 'slow',   'info2' => 'boring info' },
    'car3' => { 'info1' => 'unique', 'info2' => 'useless info' }
};
my $hr2 = {
    'new' => { 'info3' => 'rust',  'info4' => 'car1' },
    'old' => { 'info3' => 'shiny', 'info4' => 'car2 car3' }
};

my $walker = Data::Leaf::Walker->new($hr2);    
my %res;    
while ( my ($path, $value) = $walker->each ) { 
    next if $path->[-1] ne 'info4';

    # Some "values" have multiple needed values separated by space
    for my $val (split ' ', $value) { 
        # Get from 'info4' path the one to its sibling, 'info3'
        my @sibling_path = ( @{$path}[0..$#$path-1], 'info3' );

        # Collect results: values of `info3` and `info1`
        push @{$res{$val}}, 
            Dive( $hr2, @sibling_path   ), 
            Dive( $hr1, ($val, 'info1') );
    }
}
dd %res;
 

Это предполагает несколько вещей и требует некоторых сокращений, для простоты.

Во-первых, я использую явные infoN ключи из вопросов и двухуровневую структуру. Если данные отличаются или могут отличаться, это не должно быть сложно настроить.

Далее, это предполагает, что значение, как car1 всегда, существует в качестве ключа в другой хэшрефе. Добавьте exists проверку для этого ключа, если возможно, что он не существует в качестве ключа.

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

Вышеприведенная программа печатает

{
car1 => ["ржавчина", "быстро"],
car2 =>> ["блестящий", "медленный"],
car3 =>>> ["блестящий", "уникальный"],
}

(Я использую Data::Dump для отображения сложной структуры данных, для ее простоты и компактного вывода по умолчанию.)