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中的标签是否总是相同的,info1
到info4
?还是仅仅是底部(最深)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 嵌套哈希匹配和合并的主要内容,如果未能解决你的问题,请参考以下文章