Perl 无赋值的哈希加法

Perl 无赋值的哈希加法,perl,Perl,我有一个包含2个散列的脚本,当我打印出内容时,我发现脚本正在为第2个散列赋值,而我没有这样做。我先读第一个散列,然后读第二个,然后再读第二个散列。在hash2中它应该只包含1个条目,但现在它包含2个条目。如何在这里分配hash2中的值James my %hash1 = (); my %hash2 = (); $hash1{"James"}{"1 Main Street"}++; $hash1{"John"}{"2 Elm Street"}++; $hash2{"John"}{"3 Oak St

我有一个包含2个散列的脚本,当我打印出内容时,我发现脚本正在为第2个散列赋值,而我没有这样做。我先读第一个散列,然后读第二个,然后再读第二个散列。在hash2中它应该只包含1个条目,但现在它包含2个条目。如何在这里分配hash2中的值James

my %hash1 = ();
my %hash2 = ();

$hash1{"James"}{"1 Main Street"}++;
$hash1{"John"}{"2 Elm Street"}++;
$hash2{"John"}{"3 Oak Street"}++;

foreach my $name (keys %hash1) {
 print "Hash1  Name $name\n";
 foreach my $address (keys %{$hash1{$name}}) {
   print "Hash1  Address $address\n";
   foreach my $address (keys %{$hash2{$name}}) {
     print "Hash2  Address $address\n";
   }
 } 
}

print "\n";
foreach my $name (keys %hash2) {
 print "Hash2  Name $name\n";
 foreach my $address (keys %{$hash2{$name}}) {
   print "Hash2  Address $address\n";
 }
}
输出如下所示:

Hash1  Name James
Hash1  Address 1 Main Street
Hash1  Name John
Hash1  Address 2 Elm Street
Hash2  Address 3 Oak Street

Hash2  Name James
Hash2  Name John
Hash2  Address 3 Oak Street

第二个值是在尝试从散列2读取非存在密钥时创建的

my %hash1 = ();
my %hash2 = ();

$hash1{"James"}{"1 Main Street"}++;
$hash1{"John"}{"2 Elm Street"}++;
$hash2{"John"}{"3 Oak Street"}++;

foreach my $name (keys %hash1) {
 print "Hash1  Name $name\n";
 foreach my $address (keys %{$hash1{$name}}) {
   print "Hash1  Address $address\n";
   next unless exists $hash2{$name}; # check if the key exists in second hash before trying to use the key in $hash2
   foreach my $address (keys %{$hash2{$name}}) { #second value gets created here
     print "Hash2  Address $address\n";
   }
 } 
}

print "\n";
foreach my $name (keys %hash2) {
 print "Hash2  Name $name\n";
 foreach my $address (keys %{$hash2{$name}}) {
   print "Hash2  Address $address\n";
 }
}

第二个值是在尝试从散列2读取非存在密钥时创建的

my %hash1 = ();
my %hash2 = ();

$hash1{"James"}{"1 Main Street"}++;
$hash1{"John"}{"2 Elm Street"}++;
$hash2{"John"}{"3 Oak Street"}++;

foreach my $name (keys %hash1) {
 print "Hash1  Name $name\n";
 foreach my $address (keys %{$hash1{$name}}) {
   print "Hash1  Address $address\n";
   next unless exists $hash2{$name}; # check if the key exists in second hash before trying to use the key in $hash2
   foreach my $address (keys %{$hash2{$name}}) { #second value gets created here
     print "Hash2  Address $address\n";
   }
 } 
}

print "\n";
foreach my $name (keys %hash2) {
 print "Hash2  Name $name\n";
 foreach my $address (keys %{$hash2{$name}}) {
   print "Hash2  Address $address\n";
 }
}

当您将未定义的值当作引用来使用时,Perl会对所需的引用进行排序,然后尝试执行该操作。这被称为“自动活体化”

这里有一个小演示。变量一开始是未定义的。然后将其视为数组引用(获取第0个元素的解引用):

Perl将
$empty
转换为数组引用,然后尝试从中获取第0个元素。剩下的是一个数组引用,以前的
unde

$VAR1 = undef;
$VAR1 = [];
use Data::Dumper;

my @array = ( 1, 'red' );
print Dumper( \@array );

my $value = $array[5]->[0];
print Dumper( \@array );

$VAR1 = [
          1,
          'red'
        ];
$VAR1 = [
          1,
          'red',
          undef,
          undef,
          undef,
          []
        ];
这是故意的行为

更进一步。将
undef
放入数组中,并将该元素视为数组引用:

use Data::Dumper;

my @array = ( 1, undef, 'red' );
print Dumper( \@array );

my $value = $array[1]->[0];
print Dumper( \@array );
$VAR1 = [
          1,
          undef,
          'red'
        ];
$VAR1 = [
          1,
          [],
          'red'
        ];
现在,第二个元素是空数组引用:

use Data::Dumper;

my @array = ( 1, undef, 'red' );
print Dumper( \@array );

my $value = $array[1]->[0];
print Dumper( \@array );
$VAR1 = [
          1,
          undef,
          'red'
        ];
$VAR1 = [
          1,
          [],
          'red'
        ];
再进一步。不要存储
undef
值。而是访问数组中超过最后一项的数组位置:

use Data::Dumper;

my @array = ( 1, 'red' );
print Dumper( \@array );

my $value = $array[2]->[0];
print Dumper( \@array );
现在在数组中获得一个数组引用元素。它现在是一个元素:

$VAR1 = [
          1,
          'red'
        ];
$VAR1 = [
          1,
          'red',
          []
        ];
如果您更进一步(例如,元素5),那么您想要的元素之前的间隙元素将被
unde
“填充”:

$VAR1 = undef;
$VAR1 = [];
use Data::Dumper;

my @array = ( 1, 'red' );
print Dumper( \@array );

my $value = $array[5]->[0];
print Dumper( \@array );

$VAR1 = [
          1,
          'red'
        ];
$VAR1 = [
          1,
          'red',
          undef,
          undef,
          undef,
          []
        ];
散列的工作方式相同,这就是您看到的。当您想检查
James
下是否有第二级键时,Perl需要创建
James
键,并给它一个空的hash ref值,它可以进行检查。第二级钥匙不在那里,但“James”的第一级钥匙会粘在周围:

use Data::Dumper;

my %hash = (
    John => { Jay => '137' },
    );
print Dumper( \%hash );

if( exists $hash{James}{Jay} ) {
    print $hash{James}{Jay};
    }
print Dumper( \%hash );
现在,您将看到一个额外的键:

$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'James' => {},
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
在这种情况下,您不喜欢此功能,但可以使用
no autovification
pragma将其关闭。这是一个需要首先安装的CPAN模块:

no autovivification;
use Data::Dumper;

my %hash = (
    John => { Jay => '137' },
    );
print Dumper( \%hash );

if( exists $hash{James}{Jay} ) {
    print $hash{James}{Jay};
    }
print Dumper( \%hash );
您没有获得额外的密钥:

$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'James' => {},
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };

你可能也喜欢阅读。我展示了一个方法,该方法允许您在不创建中间级别的情况下检查嵌套哈希。

当您将未定义的值当作引用使用时,Perl会对所需的引用排序,然后尝试执行该操作。这被称为“自动活体化”

这里有一个小演示。变量一开始是未定义的。然后将其视为数组引用(获取第0个元素的解引用):

Perl将
$empty
转换为数组引用,然后尝试从中获取第0个元素。剩下的是一个数组引用,以前的
unde

$VAR1 = undef;
$VAR1 = [];
use Data::Dumper;

my @array = ( 1, 'red' );
print Dumper( \@array );

my $value = $array[5]->[0];
print Dumper( \@array );

$VAR1 = [
          1,
          'red'
        ];
$VAR1 = [
          1,
          'red',
          undef,
          undef,
          undef,
          []
        ];
这是故意的行为

更进一步。将
undef
放入数组中,并将该元素视为数组引用:

use Data::Dumper;

my @array = ( 1, undef, 'red' );
print Dumper( \@array );

my $value = $array[1]->[0];
print Dumper( \@array );
$VAR1 = [
          1,
          undef,
          'red'
        ];
$VAR1 = [
          1,
          [],
          'red'
        ];
现在,第二个元素是空数组引用:

use Data::Dumper;

my @array = ( 1, undef, 'red' );
print Dumper( \@array );

my $value = $array[1]->[0];
print Dumper( \@array );
$VAR1 = [
          1,
          undef,
          'red'
        ];
$VAR1 = [
          1,
          [],
          'red'
        ];
再进一步。不要存储
undef
值。而是访问数组中超过最后一项的数组位置:

use Data::Dumper;

my @array = ( 1, 'red' );
print Dumper( \@array );

my $value = $array[2]->[0];
print Dumper( \@array );
现在在数组中获得一个数组引用元素。它现在是一个元素:

$VAR1 = [
          1,
          'red'
        ];
$VAR1 = [
          1,
          'red',
          []
        ];
如果您更进一步(例如,元素5),那么您想要的元素之前的间隙元素将被
unde
“填充”:

$VAR1 = undef;
$VAR1 = [];
use Data::Dumper;

my @array = ( 1, 'red' );
print Dumper( \@array );

my $value = $array[5]->[0];
print Dumper( \@array );

$VAR1 = [
          1,
          'red'
        ];
$VAR1 = [
          1,
          'red',
          undef,
          undef,
          undef,
          []
        ];
散列的工作方式相同,这就是您看到的。当您想检查
James
下是否有第二级键时,Perl需要创建
James
键,并给它一个空的hash ref值,它可以进行检查。第二级钥匙不在那里,但“James”的第一级钥匙会粘在周围:

use Data::Dumper;

my %hash = (
    John => { Jay => '137' },
    );
print Dumper( \%hash );

if( exists $hash{James}{Jay} ) {
    print $hash{James}{Jay};
    }
print Dumper( \%hash );
现在,您将看到一个额外的键:

$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'James' => {},
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
在这种情况下,您不喜欢此功能,但可以使用
no autovification
pragma将其关闭。这是一个需要首先安装的CPAN模块:

no autovivification;
use Data::Dumper;

my %hash = (
    John => { Jay => '137' },
    );
print Dumper( \%hash );

if( exists $hash{James}{Jay} ) {
    print $hash{James}{Jay};
    }
print Dumper( \%hash );
您没有获得额外的密钥:

$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'James' => {},
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };
$VAR1 = {
          'John' => {
                      'Jay' => '137'
                    }
        };

你可能也喜欢阅读。我展示了一种方法,允许您在不创建中间层的情况下检查嵌套哈希。

对空哈希引用的不存在值
$hash2{'James'}
触发器应用hash de reference
%{}
,并因此将键
James
添加到
%hash2
@StefanBecker,而不是所有的解引用,只是那些被认为是更新的。不幸的是,它可能总是包含键,实际上,您创建了4个哈希元素而没有分配给它们:
$hash1{“James”}
$hash1{“John”}
$hash2{“James”}
$hash2{“John”}
。这一切都是由于自生。就像左值上下文中的
$$hash1{“James”}{“1 Main Street”}
${$hash1{“James”}/={}{“1 Main Street”}
的缩写,左值上下文中的
%{$hash2{$name}
%{$hash2{$name}/=}
的缩写,在不存在的值
$hash2}{James
触发空散列引用,因此也将键
James
添加到
%hash2
@StefanBecker,不是所有的解引用,只是那些被认为是更新的。不幸的是,它可能总是包含键,实际上,您创建了4个哈希元素而没有分配给它们:
$hash1{“James”}
$hash1{“John”}
$hash2{“James”}
$hash2{“John”}
。这一切都是由于自生。就像左值上下文中的
$$hash1{“James”}{“1 Main Street”}
${$hash1{“James”}/={}{“1 Main Street”}
的缩写,左值上下文中的
%{$hash2{$name}
%{$hash2{$name}/=}
的缩写,谢谢您的帮助