2015-06-05 72 views
2

我正在編寫一個腳本,用於分析文件並希望將整個結果存儲在數組中。我跑成我歸結於以下代碼中的問題:將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的輸出看來,它正確無誤,直到推送。

回答

1

你是完全正確的:

@sections =(); 

確實創建一個新的陣列,它覆蓋舊的內容。

Data::Dumper'hides'之一是參考文獻。

試試這個:

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循環很好地配合。

+0

使用'@sections = [];'正是我所需要的。謝謝。 –

1

\@sections是容器(數組)的參考@sections

@sections =()不創建新數組,但清空舊數組。要檢查兩個變量是否相同,比較它們的引用,

use strict; 
use warnings; 

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

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

本地使用'my'作爲最小代碼塊的範圍可以很好地減少這類問題。正如使用anon數組ref。 – Sobrique

+0

@Sobrique是的,這取決於你想達到什麼。 –

1

的問題是,只有一個@sections陣列,無論你做它的內容是什麼,參考\@sections將指向同一個陣列

的防振輸出顯示你這個

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

是說,$VAR2->{sections}是同一基準$VAR1->{sections},因爲他們都是一個和借鑑,這顯然是真實的e到相同的@sections陣列。它包含的數據僅僅是最新修改後剩下的數據。這是@sections2副本,將包含('sect4', 'sect5')

一些概念,可以幫助被

  • 你應該聲明變量作爲晚越好,最好在使用他們的第一點

  • 您可以編寫循環

    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", 
    }, 
] 
+0

我知道僅僅使用\ @ sections1和\ @ sections2會給我想要的結果,但是我使用了一個循環,並且數組是從文件中填充的。匿名數組[]很好。 –

+0

@PeterStaab:如果你是從一個文件定義數組,那麼 - 正如我在我的解決方案中評論的那樣 - 你正在用錯誤的範圍聲明它們。如果他們在填充和使用它們的循環中被聲明*,那麼你可以簡單地引用你最初的引用。這比用匿名數組複製信息更好,但是沒有看到更大的圖片,我無法幫助您詳細瞭解 – Borodin