Perl 嵌套哈希匹配和合并

Perl nested hashes matching and merging

我有一个文件被读取并拆分为 %objects,%objects 填充如下所示。

$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 fast rust, car2 slow shiny, car3 unique shiny”之类的数据,但我无法获得,例如“根据年龄信息 4 进行匹配”..

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"
    } 
...

有人可以指出正确的方向来获取和存储 info4 以及相关的 info1/info2 吗?

谢谢!

我取objective如下。 在最深层次的 hashref 中获取 $VAR4 中 (info4) 键的值,并在 $VAR2 hashref 中找到它们作为顶级键。然后将它们与来自 (info3) 键的值、它们自己 $VAR4 最深层次 hashref 中的“兄弟”以及键值 (info1 ) 来自 $VAR2.

可以为此目的手动遍历结构,特别是如果它始终具有如图所示的相同两个级别,但使用库更容易和更好。我使用 Data::Leaf::Walker to get leaves (deepest values) and key-paths to them, and 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 这样的值始终作为另一个 hashref 中的键存在。添加一个 exists 检查该键,如果它可能不作为键存在。

我从数据中删除了一些额外的引号。 (如果这是用于数据库条目,请在构造语句时执行此操作。如果数据带有此类额外引号,则调整代码以将其考虑在内应该很容易。)

以上程序打印

{
  car1 => ["rust", "fast"],
  car2 => ["shiny", "slow"],
  car3 => ["shiny", "unique"],
}

(我使用 Data::Dump 来显示复杂的数据结构,因为它的简单性和默认的紧凑输出。)