【问题标题】:Hash adding value without assignment [duplicate]没有赋值的哈希添加值[重复]
【发布时间】:2019-07-14 13:50:27
【问题描述】:

我有一个包含 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

【问题讨论】:

  • 在不存在的值$hash2{'James'} 上应用散列取消引用%{} 会触发空散列引用的autovivification,因此还会将键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} //= {} } 的缩写。

标签: perl


【解决方案1】:

当您尝试从哈希 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】:

当你把一个未定义的值当作一个引用来使用时,Perl 会对你想要的引用进行排序,然后尝试执行操作。这称为“自动复活”。

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

use Data::Dumper;

my $empty;
print Dumper( $empty );

my $value = $empty->[0];
print Dumper( $empty );

Perl 将$empty 转换为数组引用,然后尝试从中获取第 0 个元素。你留下了一个数组引用,你以前有undef

$VAR1 = undef;
$VAR1 = [];

这是预期的行为。

更进一步。将 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'
        ];

更进一步。不要存储 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),直到你想要的元素的插页式元素将被“填充”为undef

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 值,它可以检查。二级键不存在,但“詹姆斯”的一级键仍然存在:

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'
                    }
        };

在这种情况下,您不喜欢此功能,但您可以使用 no autovivification 杂注将其关闭。这是您需要先安装的 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 = {
          'John' => {
                      'Jay' => '137'
                    }
        };

您可能还想阅读How can I check if a key exists in a deep Perl hash?。我展示了一种方法,该方法允许您检查嵌套哈希而不创建中间级别。

【讨论】:

    猜你喜欢
    • 2015-08-09
    • 2022-07-21
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-22
    • 2011-07-28
    相关资源
    最近更新 更多