在perl中构建hash的hash



我是使用perl的新手,我正在尝试从tsv构建一个散列的散列。我目前的流程是读入一个文件,构造一个哈希,然后将其插入另一个哈希中。

   my %hoh = ();
   while (my $line = <$tsv>) 
   {
      chomp $line;
      my %hash;
      my @data = split "t", $line;
      my $id;
      my $iter = each_array(@columns, @data);
      while(my($k, $v) = $iter->())
      {
         $hash{$k} = $v;
         if($k eq 'Id')
         {
            $id = $v;   
         }
      }
      $hoh{$id} = %hash;
   }
   print "dump: ", Dumper(%hoh);

该输出:

dump
$VAR1 = '1234567890';
$VAR2 = '17/32';
$VAR3 = '1234567891';
$VAR4 = '17/32';
.....

而不是我所期望的:

dump
{
   '1234567890' => { 
                    'k1' => 'v1',
                    'k2' => 'v2',
                    'k3' => 'v3',
                    'k4' => 'v4',
                    'id' => '1234567890'
                   },
   '1234567891' => { 
                    'k1' => 'v1',
                    'k2' => 'v2',
                    'k3' => 'v3',
                    'k4' => 'v4',
                    'id' => '1234567891'
                   },
     ........
};

我有限的理解是,当我执行$hoh{$id} = %hash;时,它在%hash的引用中的插入?我做错了什么?还有没有一种更简洁的方法可以将我的列和数据数组作为键、值对使用到我的%hash对象中?

-提前感谢,Niru

要获得引用,必须使用:

$hoh{$id} = %hash;

%hash是散列,而不是对它的引用。在标量上下文中,它返回字符串X/Y,其中X是已使用的桶的数量,Y是散列中所有桶的数量(即没有任何用处)。

要获得对哈希变量的引用,需要使用%hash(正如choroba所说)。

将值分配给列的一种更简洁的方法是分配给哈希片,如下所示:

my %hoh = ();
while (my $line = <$tsv>) 
{
   chomp $line;
   my %hash;
   @hash{@columns} = split "t", $line;
   $hoh{$hash{Id}} = %hash;
}
print "dump: ", Dumper(%hoh);

散列切片(@hash{@columns})的含义与($hash{$columns[0]}, $hash{$columns[1]}, $hash{$columns[2]}, ...)基本相同,最多可以有多少列。通过分配,我将第一个值从split分配给$hash{$columns[0]},第二个值分配给$hash{$columns[1]},依此类推。它的作用与while ... $iter循环完全相同,只是没有显式循环(而且它不会提取$id)。

不需要在循环内比较每个$k'Id';只需将其作为普通字段存储在散列中,然后用CCD_ 15提取即可。(旁白:你的列标题是Id还是id?你在循环中使用Id,但在预期输出中使用了id。)

如果您不想在单个条目中保留Id字段,可以使用delete(从散列中删除密钥并返回值):

$hoh{delete $hash{Id}} = %hash;

看看Perl中包含的文档。命令perldoc非常有用。您也可以查看Perldoc的网页。

其中一个教程是关于Perl参考的教程。这一切都有助于澄清你的许多问题,并解释关于引用和取消引用的问题。

我还建议您查看CPAN。这是一个各种Perl模块的档案,可以执行许多不同的任务。查看文本::CSV。这个模块将完全按照您的意愿进行操作,即使上面写着"CSV",它也可以使用制表符分隔的文件。

你错过了在你的哈希前面加一个斜线——你正试图做一个参考。您有:

$hoh{$id} = %hash;

可能需要:

$hoh{$id} = %hash;

此外,当您对哈希执行Data::Dumper时,您应该在对哈希的引用上执行该操作。在内部,当Data::Dumper转储完成时,散列和数组具有类似的结构。

您有:

 print "dump: ", Dumper(%hoh);

你应该有:

 print "dump: ", Dumper( %hoh );

我尝试的程序:

#! /usr/bin/env perl
#
use warnings;
use strict;
use autodie;
use feature qw(say);
use Data::Dumper;
use constant {
    FILE    => "test.txt",
};
open my $fh, "<", FILE;
#
# First line with headers
#
my $line = <$fh>;
chomp $line;
my @headers = split /t/, $line;
my %hash_of_hashes;
#
# Rest of file
#
while ( my $line = <$fh> ) {
    chomp $line;
    my %line_hash;
    my @values = split /t/, $line;
    for my $index ( ( 0..$#values ) ) {
        $line_hash{ $headers[$index] } = $values[ $index ];
    }
    $hash_of_hashes{ $line_hash{id} } = %line_hash;
}
say Dumper %hash_of_hashes;

只有在变量超出作用域之前的最后一行中存储对变量的引用,才应该存储对该变量的引用。在脚本中,您在while循环中声明%hash,因此将此语句作为循环中的最后一个语句是安全的:

$hoh{$id} = %hash;

如果它不是最后一条语句(或者您不确定它是否安全),请创建一个匿名结构来保存变量的内容:

$hoh{$id} = { %hash };

这会生成%hash的副本,速度较慢,但对其进行的任何后续更改都不会影响您存储的内容。

最新更新