如何合并Perl中包含哈希的数组并去除重复哈希元素
你遇到的问题本质是List::MoreUtils的uniq函数基于元素字符串化结果去重,而数组中存储的是哈希引用,字符串化后得到的是内存地址(如HASH(0xabc123)),两个内容完全一致的哈希引用只要是不同的实例,内存地址就不同,因此无法被识别为重复项。
方案1:合并后轻量去重(适合固定结构场景)
如果你当前的哈希结构固定只有sport和country两个判断重复的字段,可以直接拼接两个字段值作为去重标识,无需引入额外模块:
use strict; use Hash::Merge qw/merge/; use Data::Dumper; my $h1 = { name1 => [ { sport => "tennis", country => "us", }, { sport => "soccer", country => "brazil", }, { sport => "cricket", country => "india" }, ] }; my $h2 = { name1 => [ { sport => "soccer", country => "brazil", }, { sport => "boxing", country => "china" } ], }; # 执行默认合并 my $merged = merge($h1, $h2); # 对合并后的数组去重 my %seen; $merged->{name1} = [ grep { !$seen{$_->{sport} . '|' . $_->{country}}++ } @{$merged->{name1}} ]; print Dumper($merged);
方案2:自定义Hash::Merge合并规则(一次配置全局生效)
如果希望合并时自动完成去重,不需要后续单独处理,可以自定义Hash::Merge的数组合并行为:
use strict; use Hash::Merge qw/merge/; use Data::Dumper; # 注册自定义合并规则 Hash::Merge::specify_behavior( { 'SCALAR' => { 'SCALAR' => sub { $_[1] }, 'ARRAY' => sub { [ $_[0], @{$_[1]} ] }, 'HASH' => sub { $_[1] }, }, 'ARRAY' => { 'SCALAR' => sub { [ @{$_[0]}, $_[1] ] }, 'ARRAY' => sub { my %seen; my @combined = (@{$_[0]}, @{$_[1]}); # 可根据实际字段调整去重标识拼接规则 [ grep { !$seen{$_->{sport} . '|' . $_->{country}}++ } @combined ]; }, 'HASH' => sub { $_[1] }, }, 'HASH' => { 'SCALAR' => sub { $_[1] }, 'ARRAY' => sub { $_[1] }, 'HASH' => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) }, }, }, 'ARRAY_WITH_UNIQUE_HASH' ); # 启用自定义规则 Hash::Merge::set_behavior('ARRAY_WITH_UNIQUE_HASH'); my $h1 = { name1 => [ { sport => "tennis", country => "us", }, { sport => "soccer", country => "brazil", }, { sport => "cricket", country => "india" }, ] }; my $h2 = { name1 => [ { sport => "soccer", country => "brazil", }, { sport => "boxing", country => "china" } ], }; # 直接合并即可自动去重 my $merged = merge($h1, $h2); print Dumper($merged);
两种方案最终输出的结果都会去掉重复的{sport => "soccer", country => "brazil"}项:
$VAR1 = { 'name1' => [ { 'country' => 'us', 'sport' => 'tennis' }, { 'country' => 'brazil', 'sport' => 'soccer' }, { 'sport' => 'cricket', 'country' => 'india' }, { 'country' => 'china', 'sport' => 'boxing' } ] };
如果你的哈希结构不固定,判断重复需要匹配所有键值,可以用JSON::PP或者Storable模块把哈希序列化为字符串作为去重标识,替换掉上面的字段拼接逻辑即可。
内容的提问来源于stack exchange,提问作者kathy
相关产品推荐
相关产品推荐

