合并 Perl Hashrefs 和 unique

Merge Perl Hashrefs and unique

我有两个具有以下内容的 perl 散列:

第一个:

$VAR1 = {
      'name1' => [
                   'adam',
                   'bob'
                 ],
      'name2' => [
                  'Miller',
                  'Schumacher'
                ]
    };

第二个:

$VAR1 = {
      'name1' => [
                   'tina',
                   'jason',
                   'jeff'
                 ],
      'name2' => [
                  'Miller',
                  'Schumacher',
                  'Schmidt'
                ]
    };

如何合并它们以获得以下结构并在 name2 中获得唯一项?

$VAR1 = {
      'name1' => [
                   'tina',
                   'jason',
                   'jeff',
                   'adam',
                   'bob',
                 ],
      'name2' => [
                  'Miller',
                  'Schumacher',
                  'Schmidt'
                ]
    };

您必须遍历 name1, name2 个键并从 $VAR2->{$k}$VAR1->{$k} 数组中过滤重复项,

use strict;
use warnings;

my $VAR1 = {
      'name1' => [ 'adam', 'bob' ],
      'name2' => [ 'Miller', 'Schumacher' ]
};
my $VAR2 = {
      'name1' => [ 'tina', 'jason', 'jeff' ],
      'name2' => [ 'Miller', 'Schumacher', 'Schmidt' ]
};

my %result;
for my $k (keys %$VAR1) {
  my %seen;
  $result{$k} = [
    grep { !$seen{$_}++ } @{ $VAR2->{$k} }, @{ $VAR1->{$k} }
  ];
}

use Data::Dumper;
print Dumper \%result;

输出

$VAR1 = {
      'name2' => [
                   'Miller',
                   'Schumacher',
                   'Schmidt'
                 ],
      'name1' => [
                   'tina',
                   'jason',
                   'jeff',
                   'adam',
                   'bob'
                 ]
    };

如果您的需求非常具体——用键 name1name2 合并两个散列,那么下面应该可以解决问题:

my $first = {
        name1 => [ qw(adam bob) ],
        name2 => [ qw(Miller Schumacher) ],
    };
my $second = {
        name1 => [ qw(tina jason jeff) ],
        name2 => [ qw(Miller Schumacher Schmidt) ],
    };

my $merged = {
        name1 => [ values %{$first->{name1}}, values %{$second->{name1}} ],
        name2 => [ values %{$first->{name2}}, values %{$second->{name2}} ],
    };

如果密钥不固定且事先已知,Сухой27 的答案将有效,至少在结构只有两层深的情况下。 如果它可以更深入,你将需要一个递归解决方案。

这是一个通用的解决方案,可以采用任意数量的散列,并处理任何散列中丢失的键

它遍历所有要组合的散列键的列表,并使用 map

将所有散列中每个键的数组值连接起来

我使用Data::Dump只是为了显示结果哈希数据

use strict;
use warnings;

use List::MoreUtils qw/ uniq /;
use Data::Dump;

my %ha = (
    name1 => [ "adam",   "bob" ],
    name2 => [ "Miller", "Schumacher" ],
);

my %hb = (
    name1 => [ "tina",   "jason",      "jeff" ],
    name2 => [ "Miller", "Schumacher", "Schmidt" ],
);

my @hashes = \( %ha, %hb );

my %new;

for my $k ( uniq map keys %$_, @hashes ) {
    $new{$k} = [
        uniq map @{ $_->{$k} // [] }, @hashes
    ];
}

dd \%new;

输出

{
  name1 => ["adam", "bob", "tina", "jason", "jeff"],
  name2 => ["Miller", "Schumacher", "Schmidt"],
}

如果出于任何原因您不想安装非核心库模块List::MoreUtils,那么您可以使用此版本的uniq 函数

sub uniq {
  my %seen;
  grep { not $seen{$_}++ } @_;
}

Hash::Merge 自定义模块的右先例行为以在合并数组时统一元素。

use strict;
use Hash::Merge qw/merge :custom/;
use List::MoreUtils qw/uniq/;
use Data::Dumper;

my $href1 = { name1 => [ qw/adam bob/ ],
              name2 => [ qw/Miller Schumacher/ ] };

my $href2 = { name1 => [ qw/tina jason jeff/ ],
              name2 => [ qw/Miller Schumacher Schmidt/ ] };

Hash::Merge::specify_behavior(  {
                        SCALAR => {
                                SCALAR => sub { $_[1] },
                                ARRAY  => sub { [ $_[0], @{$_[1]} ] },
                                HASH   => sub { $_[1] },
                        },
                        ARRAY => {
                                SCALAR => sub { $_[1] },
                                # This returns unique elements from two arrays passed
                                ARRAY  => sub { [ uniq( @{$_[0]}, @{$_[1]}) ] },
                                HASH   => sub { $_[1] }, 
                        },
                        HASH => {
                                SCALAR => sub { $_[1] },
                                ARRAY  => sub { [ values %{$_[0]}, @{$_[1]} ] },
                                HASH   => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) }, 
                        },
                }, 
                'Right precedent + Uniq array', 
        );

my $href3 = merge($href1, $href2);

print Dumper $href3;

产生输出:

$VAR1 = {
          'name2' => [
                       'Miller',
                       'Schumacher',
                       'Schmidt'
                     ],
          'name1' => [
                       'adam',
                       'bob',
                       'tina',
                       'jason',
                       'jeff'
                     ]
        };