【问题标题】:Perl: array and hashPerl:数组和哈希
【发布时间】:2017-02-24 06:44:18
【问题描述】:

除了找到我之前的问题Perl: slicing an array of hashes 的答案之外,我再次陷入困境,无法看到我做错了什么。

我拥有的是

Array(Array0(Hash0,Hash1),Array1(Hash0,Hash1),Array2(Hash0,Hash1)...)

use strict;
use warnings;

my @DDs = ();
my @Ds  = ();
my %hsh = ();

my %dot1 = ( 'x' => 1,   'y' => 2,   'r' => 3 );
my %dot2 = ( 'x' => 4,   'y' => 5,   'r' => 6 );
my %dot3 = ( 'x' => 7,   'y' => 8,   'r' => 9 );
my %dot4 = ( 'x' => 1.1, 'y' => 1.2, 'r' => 1.3 );
my %dot5 = ( 'x' => 2.1, 'y' => 2.2, 'r' => 2.3 );
my %dot6 = ( 'x' => 3.1, 'y' => 3.2, 'r' => 3.3 );
my %dot7 = ( 'x' => 4.1, 'y' => 4.2, 'r' => 4.3 );
my %dot8 = ( 'x' => 5.1, 'y' => 5.2, 'r' => 5.3 );

my @dotsA = ( \%dot1, \%dot2 );
my @dotsB = ( \%dot3, \%dot4 );
my @dotsC = ( \%dot5, \%dot6 );
my @dotsD = ( \%dot7, \%dot8 );

my %Ds = ( \@dotsA, \@dotsB, \@dotsC, \@dotsD );

@DDs = $Ds[1];    #expect @dotsB with scalar of 2

###"Can't use an undefined value as HASH reference" error here
%hsh = %{ $DDs[0] };    #expect %dot3

print scalar @DDs, "\n";    #expect 2 but has value of 1
print $hsh{'x'}, "\n";

【问题讨论】:

  • 您同时拥有%Ds@Ds。您分配给%Ds,但@Ds 仍然为空。 $Ds[1]@Ds 中选择一个值,这当然是未定义的,因为其中没有任何内容。 @DDs 成为一个包含 1 个未定义标量的数组。 $DDs[0] 是未定义的标量。
  • 使用数字后缀(%dot1%dot2)命名变量是主要的代码异味。你能解释一下你到底想要达到什么目的吗?几乎可以肯定有一种更清洁的方法。
  • @ThisSuitIsBlackNot,数字后缀并不打算在最终版本中使用,只是测试这种特殊方法。尝试创建具有多个属性的项目“系列”(为了测试,我选择了具有 x、y 坐标和半径的点)。这些项目哈希被分组到一个家庭数组中(测试中的两个项目)。家庭属于“群体”。尝试针对组中的项目属性运行测试,然后允许将一些项目系列推入组中。 .

标签: arrays perl


【解决方案1】:

在 /Users/schwern/tmp/test.plx 第 10 行的预期大小列表中找到了参考。

第 10 行是这样的:

my %dot1 = {'x'=>1,'y'=>2,'r'=>3};

这是 Perl 的一种神秘方式,即您将哈希引用提供给哈希。不幸的是,Perl 对事物和对该事物的引用进行了非常严格的区分。

%dot1 是一个哈希值。它需要一个列表并将其转换为哈希。像( x => 1, y => 2, r => 3) 这样的列表。 { x => 1, y => 2, r => 3 } 创建一个哈希引用。这是一个单一的东西,一个标量。这就像说my %dot1 = (42)。这没有任何意义。

  • %dot1 是一个哈希,它想要一个像(x => 1, y => 2) 这样的列表
  • $dot1 是一个标量,它可以存储像{ x => 1, y => 2 } 这样的哈希引用。

my %Ds = (\@dotsA,\@dotsB,\@dotsC,\@dotsD);

哈希需要一个键和一个值,对。 last_name => "Schwern"。当你给它一堆这样的数组引用时,它会将它们读取为 key1、value1、key2、value2 ......但它使用什么作为 key?它正在使用该引用的字符串化,例如ARRAY(0x7fb721800468)

如果您要求$D{\@dotsA},您将获得对@dotsB 的引用。您将无法返回 @dotsA,Perl 哈希键只是一个字符串,而不是一个引用。

这不是在散列中存储数组的好方法。我不确定您要完成什么,但您可能想按名称引用它们。

# A hash of lists.
my %Ds = ( A => \@dotsA, B => \@dotsB, C => \@dotsC, D => \@dotsD );

# Get back a reference to @dotsA.
my $dotsA = $Ds{A};

但是看看下面的代码@DDs = $Ds[1];,我想你的意思是初始化@Ds而不是%Ds

@Ds = (\@dotsA,\@dotsB,\@dotsC,\@dotsD);

现在下面的作品......有点。稍后再说。

@DDs = $Ds[1]; #expect @dotsB with scalar of 2

与 PHP 不同,哈希和数组是完全不同的东西。 my @Dsmy %Ds 声明完全不同的变量。使用$Ds 访问它们并没有帮助。在 Perl5 中,印记指示将要返回的内容。 $Ds[1]$Ds{foo} 都使用 $Ds 因为它们返回一个标量。 @Ds[1,2]@Ds{(foo, bar)} 使用 @Ds 因为它们返回一个列表(称为切片)。令人困惑,但这就是它的工作原理。


@DDs = $Ds[1]; #expect @dotsB with scalar of 2

你没有得到@dotsB,你得到的是@dotsB的引用。 Perl 中的所有复杂数据结构都存储引用,而不是实际值。这就像$DDs[0] = \@dotsB。如果您想获得实际值,则必须取消引用它。

@DDs = @{$Ds[1]};  # Now @DDs has a copy of @dotsB

终于成功了。

#!/usr/bin/perl
use strict;
use warnings;
use v5.10;    # for say()

my %dot1 = ('x'=>1,'y'=>2,'r'=>3);
my %dot2 = ('x'=>4,'y'=>5,'r'=>6);
my %dot3 = ('x'=>7,'y'=>8,'r'=>9);
my %dot4 = ('x'=>1.1,'y'=>1.2,'r'=>1.3);
my %dot5 = ('x'=>2.1,'y'=>2.2,'r'=>2.3);
my %dot6 = ('x'=>3.1,'y'=>3.2,'r'=>3.3);
my %dot7 = ('x'=>4.1,'y'=>4.2,'r'=>4.3);
my %dot8 = ('x'=>5.1,'y'=>5.2,'r'=>5.3);

my @dotsA = (\%dot1,\%dot2);
my @dotsB = (\%dot3,\%dot4);
my @dotsC = (\%dot5,\%dot6);
my @dotsD = (\%dot7,\%dot8);

my @Ds = (\@dotsA,\@dotsB,\@dotsC,\@dotsD);
my @DDs = @{$Ds[1]}; #expect @dotsB

my %hsh = %{$DDs[0]}; #expect %dot3

say scalar @DDs; #expect 2
say $hsh{'x'};

我还建议您习惯于直接使用引用,因为这就是复杂的数据结构:引用。从引用到值来回转换是令人困惑的。使用引用是在您的代码中、在您的头脑中转换的一件事,并且在您的程序中完成的复制更少。

#!/usr/bin/perl
use strict;
use warnings;
use v5.10;    # for say()

my $dot1 = {'x'=>1,'y'=>2,'r'=>3};
my $dot2 = {'x'=>4,'y'=>5,'r'=>6};
my $dot3 = {'x'=>7,'y'=>8,'r'=>9};
my $dot4 = {'x'=>1.1,'y'=>1.2,'r'=>1.3};
my $dot5 = {'x'=>2.1,'y'=>2.2,'r'=>2.3};
my $dot6 = {'x'=>3.1,'y'=>3.2,'r'=>3.3};
my $dot7 = {'x'=>4.1,'y'=>4.2,'r'=>4.3};
my $dot8 = {'x'=>5.1,'y'=>5.2,'r'=>5.3};

my $dotsA = [$dot1,$dot2];
my $dotsB = [$dot3,$dot4];
my $dotsC = [$dot5,$dot6];
my $dotsD = [$dot7,$dot8];

my $Ds = [$dotsA,$dotsB,$dotsC,$dotsD];
my $DDs = $Ds->[1]; #expect $dotsB

my $hsh = $DDs->[0]; #expect $dot3

say scalar @$DDs; #expect 2
say $hsh->{'x'};

您应该查看perlreftutNested Data Structures chapter of Modern Perl

【讨论】:

  • 非常感谢@Schwern 的详细解释。我在哈希定义中看到了 {} 错误并编辑了问题。然后我最终注意到,当我想使用数组时,我有 %Ds - 逐行浏览代码,直到发布问题后才能看到它。我现在看到了 @DDs=@{$Dx[1]} 部分。太感谢了。嵌套数据结构章节很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-28
  • 2016-06-06
  • 2014-05-12
  • 2020-07-19
  • 2011-07-02
  • 2012-08-22
  • 2012-06-12
相关资源
最近更新 更多