Perl 嵌套哈希匹配和合并

Posted

技术标签:

【中文标题】Perl 嵌套哈希匹配和合并【英文标题】:Perl nested hashes matching and merging 【发布时间】:2021-11-28 16:58:07 【问题描述】:

我有一个文件被读取并拆分为 %ojects,%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 快速生锈、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"
     
...

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

谢谢!

【问题讨论】:

它有什么关系——是因为info4 的值car1 是第二个hashref $VAR2 中的一个键吗?似乎您只需要仔细迭代这些数据结构。顺便说一句,请在代码中添加显示的转储中的哪个数据结构。代码中只有一个 (%objects) 但转储显示多个。 是的,这就是它们之间的关系以及我正在努力弄清楚如何匹配的方式。代码示例应该只提供 VAR1 和 VAR2 的输出,因为我正在努力匹配和检索其余数据。如果我继续通过添加另一个 $obj2 和 $key2 来绕过漏洞(foreach),我最终会得到一堆条目,比如每辆车都会快速、缓慢和独特等。 二级hashref中的标签是否总是相同的,info1info4?还是仅仅是底部(最深)hashref 中的两个键值对? 它总是相同的标签,所以答案被接受。使用 Data::Leaf::Walker 获得最深值的好技巧。我会看看我能不能玩弄这个来适应整个事情,太棒了! 【参考方案1】:

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

为此,可以手动遍历结构,特别是如果它始终具有与所示相同的两个级别,但使用库更容易更好。我使用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 这样的值始终作为键存在于另一个hashref 中。添加一个exists 检查该密钥是否可能不作为密钥存在。

我从数据中删除了一些额外的引号。 (如果那是为了数据库输入,在构造语句时这样做。如果数据带有这样的额外引号,则应该很容易调整代码以将它们考虑在内。)

上面的程序打印

car1 => [“锈”,“快”], car2 => [“闪亮”,“慢”], car3 => [“闪亮”,“独特”],

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

【讨论】:

以上是关于Perl 嵌套哈希匹配和合并的主要内容,如果未能解决你的问题,请参考以下文章

perl中如何把数组最为hash的key

如何递归地分配 perl 多维哈希的键的值,其中该键类似于嵌套键的值?

为啥在合并另一个哈希时会更新嵌套哈希的所有值?

Perl:标量,数组,哈希

请问怎么给perl里的标量,哈希,数组赋初值?

perl 将数组的元素对应为hash的key 和value