如何基于哈希引用的列值访问哈希引用数组?
问题描述
我通过fetchrow_hashref()从数据库构建了一个哈希引用数组,数据结构构建代码如下:
while (my $ref = $sth->fetchrow_hashref()) { push @lines, $ref; }
数据已按program name升序排序,数组中的引用保持字母顺序。随后我遍历每个哈希,找到值等于'1'的键,获取列名并存储,用来对比同program name的其他哈希引用是否在同一列都有'1',相关代码如下:
my $pgm = ""; my $met_lvl = ""; my @devs = (); my %errors = (); my $error = ""; foreach my $line_ref (@lines) { if ($pgm ne $line_ref->{"PROGRAM"}) { if (@devs && $error) { # print " Different number metal layers for $pgm: @devs \n"; $error = ""; } @devs = (); $pgm = $line_ref->{"PROGRAM"}; ($met_lvl) = grep { $line_ref->{$_} == 1 } keys(%$line_ref); push @devs, $line_ref->{"DEVICE"}; } elsif ($pgm eq $line_ref->{"PROGRAM"}) { push @devs, $line_ref->{"DEVICE"}; my ($met_chk ) = grep { $line_ref->{$_} == 1 } keys(%$line_ref); if ($met_chk ne $met_lvl) { $errors{$line_ref->{"PROGRAM"}} = $line_ref->{"PROGRAM"}; $error = "YUP"; } } }
我希望能基于数据库列名匹配来单独访问哈希引用,比如如何访问PROGRAM键值为"TEST"的哈希引用?以下是示例哈希引用:
{ 'PLM' => undef, 'SLM' => undef, 'QLM' => undef, 'DEVICE' => 'DEV1', 'TLM' => '1', 'DLM' => undef, 'ROUTING' => 'NORMAL', 'PROGRAM' => 'TEST' }; $VAR455 = { 'PLM' => undef, 'SLM' => undef, 'QLM' => undef, 'DEVICE' => 'DEV2', 'TLM' => '1', 'DLM' => undef, 'ROUTING' => 'NORMAL', 'PROGRAM' => 'TEST' }; $VAR456 = { 'PLM' => undef, 'SLM' => undef, 'QLM' => undef, 'DEVICE' => 'DEV3', 'TLM' => '1', 'DLM' => undef, 'ROUTING' => 'NON_STANDARD', 'PROGRAM' => 'EXP' }; $VAR457 = { 'PLM' => undef, 'SLM' => undef, 'QLM' => undef, 'DEVICE' => 'DEV4', 'TLM' => '1', 'DLM' => undef, 'ROUTING' => 'NORMAL', 'PROGRAM' => 'FINAL' };
我需要访问具有相同program name的哈希引用的键值,推测可以用map,但不清楚如何解引用数组中每个哈希引用的"PROGRAM"值。补充说明:访问同PROGRAM值的哈希引用,是为了将选定值输出到日志文件,在对比发现差异后,再次访问它们并打印所需列值到日志。
解决方案
方法1:用grep直接筛选目标哈希引用
直接通过grep遍历数组,筛选出PROGRAM值匹配的哈希引用:
# 获取所有PROGRAM为"TEST"的哈希引用 my @test_programs = grep { $_->{"PROGRAM"} eq "TEST" } @lines; # 遍历输出这些哈希的DEVICE和ROUTING值到日志 foreach my $ref (@test_programs) { print LOG "PROGRAM: $ref->{PROGRAM}, DEVICE: $ref->{DEVICE}, ROUTING: $ref->{ROUTING}\n"; }
方法2:提前构建分组哈希(高效复用)
如果需要多次按PROGRAM分组访问数据,建议先把数组转换成以PROGRAM为键的哈希,值是对应哈希引用的数组,后续访问会更高效:
# 构建分组哈希 my %program_groups; foreach my $ref (@lines) { my $pgm_name = $ref->{"PROGRAM"}; push @{$program_groups{$pgm_name}}, $ref; } # 访问PROGRAM为"TEST"的所有哈希引用 my @test_refs = @{$program_groups{"TEST"}}; # 输出到日志 foreach my $ref (@test_refs) { print LOG "DEVICE: $ref->{DEVICE}, TLM: $ref->{TLM}\n"; } # 针对之前检测到的错误PROGRAM,直接输出对应数据 foreach my $err_pgm (keys %errors) { my @err_refs = @{$program_groups{$err_pgm}}; print LOG "ERROR - PROGRAM $err_pgm has inconsistent metal layers:\n"; foreach my $ref (@err_refs) { my ($met_col) = grep { $ref->{$_} eq '1' } keys %$ref; print LOG " DEVICE: $ref->{DEVICE}, Metal Layer: $met_col\n"; } }
map的使用示例
如果想用map提取特定字段,比如获取所有"TEST" PROGRAM对应的DEVICE列表:
my @test_devices = map { $_->{"PROGRAM"} eq "TEST" ? $_->{"DEVICE"} : () } @lines; # 输出结果:('DEV1', 'DEV2')
内容的提问来源于stack exchange,提问作者WetCheerios
相关产品推荐
相关产品推荐

