将Perl数组放入哈希

时间:2015-06-05 12:18:58

标签: arrays perl

我正在编写一个解析文件的脚本,并希望将整个结果放在一个数组中。我遇到了一个问题,我将其归结为以下代码:

use strict;
use warnings;

use Data::Dumper;

my @sections  = ();
my @sections1 = qw/sect1 sect2 sect3/;
my @sections2 = qw/sect4 sect5/;

my @textbooks = ();

my $text1 = { title => "title1", author => "author1" };
my $text2 = { title => "title2", author => "author2" };

for ( @sections1 ) {
  push(@sections, $_);
}
$text1->{sections} = \@sections;
@sections = ();

for ( @sections2 ) {
  push(@sections, $_);
}

push(@textbooks, $text1);
$text2->{sections} = \@sections;
print Dumper($text2);

push(@textbooks, $text2);

print Dumper(@textbooks);

第一个打印翻斗车的结果如下:

$VAR1 = {
          'title' => 'title2',
          'sections' => [
                          'sect4',
                          'sect5'
                        ],
          'author' => 'author2'
        }

,第二个结果是:

$VAR1 = {
          'sections' => [
                          'sect4',
                          'sect5'
                        ],
          'title' => 'title1',
          'author' => 'author1'
        };
$VAR2 = {
          'title' => 'title2',
          'sections' => $VAR1->{'sections'},
          'author' => 'author2'
        };

我有两个问题,我确信这是相关的。

  • 我意识到第一部分是一个参考,所以它们包含我期望的第二部分。我认为行@sections=()将创建一个新数组,稍后将创建一个新引用。显然我没有正确地考虑这个问题。

  • 第二节的内容是什么?从$text2的输出看起来它是正确的,直到推送。

3 个答案:

答案 0 :(得分:1)

\@sections是对@sections容器(数组)的引用。

@sections = ()不会创建新数组,但会清空旧数组。要检查两个变量是否相同,请比较它们的引用,

use strict;
use warnings;

my @sections = 1 .. 3;
my $ref1 = \@sections;
@sections = ();

print "identical!\n" if $ref1 == \@sections;

答案 1 :(得分:1)

问题是只有一个@sections数组,无论你对它的内容做什么,引用\@sections都将引用相同的数组

转储器输出显示此

$VAR2 = {
          'title' => 'title2',
          'sections' => $VAR1->{'sections'},
          'author' => 'author2'
        };

表示$VAR2->{sections}$VAR1->{sections}的引用相同,这显然是正确的,因为它们都是对同一@sections数组的引用。它包含的数据只是在最新修改后留下的数据。这是@sections2的副本,其中包含('sect4', 'sect5')

可能有帮助的一些概念

  • 您应该尽可能将变量声明为 late ,最好是在他们的第一个使用点

  • 您可以编写循环

    for ( @sections1 ) {
      push(@sections, $_);
    }
    

    只是

    push @sections, @sections1
    
  • 而不是

    $text1->{sections} = \@sections
    

    分配对数组@sections的引用,您可以使用

    $text1->{sections} = [ @sections ]
    

    创建一个新的匿名数组,从@sections的内容填充它,并返回对它的引用。这样,您就可以自由修改@sections而无需更改已保存在$text1

  • 中的数据副本

你的代码可能应该写成这样的代码,但你还没有说过你想对数据做些什么,所以你可能需要做一些改变

我强烈建议您优先使用Data::Dump Data::Dumper。您可能需要安装它,因为它不是核心模块,但它非常值得,因为转储输出更整洁,更简洁,更易读

use strict;
use warnings;

use Data::Dump;

my @sections1 = qw/ sect1 sect2 sect3 /;
my @sections2 = qw/ sect4 sect5 /;

my @textbooks = (
  { title => 'title1', author => 'author1' },
  { title => 'title2', author => 'author2' },
);

$textbooks[0]{sections} = \@sections1;
$textbooks[1]{sections} = \@sections2;

dd \@textbooks;

<强>输出

[
  {
    author   => "author1",
    sections => ["sect1", "sect2", "sect3"],
    title    => "title1",
  },
  {
    author => "author2",
    sections => ["sect4", "sect5"],
    title => "title2",
  },
]

答案 2 :(得分:1)

你完全正确:

@sections = (); 

NOT 创建一个新数组,它会覆盖旧数组的内容。

Data::Dumper'隐藏'之一就是引用。

试试这个:

foreach my $key ( keys %{$text2} ) { 
   print $key, $text2 -> {$key},"\n"
}

foreach my $thing (@textbooks) {
    print "TB ref $thing\n";
    foreach my $key ( keys %{$thing} ) {
        print "$key => ", $thing->{$key}, "\n";
    }
}

从后者,你会得到类似的东西:

TB ref HASH(0x12de994)
sections => ARRAY(0x12e43b4)
author => author1
title => title1
TB ref HASH(0x12de9ac)
sections => ARRAY(0x12e43b4)
title => title2
author => author2

注意数组在这里具有相同的ID - 这是您问题的根源。您的哈希两次具有相同的引用。 (哈希数组中的父hashes不同)

一个简单的解决方法可能是从使用@sections切换到$sections,因为在以下情况下:

@sections = ();

不构成“新”数据结构:

$sections = []; 

因为[]是一个匿名数组,你正在创建,只是重新分配引用。

另一种解决方案通常是使用my缩小范围,但是使用的代码不能很好地工作 - 尽管可以很好地使用foreach循环。

相关问题