0

我是使用 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 对象中吗?

-提前致谢,尼鲁

4

4 回答 4

2

要获得参考,您必须使用\

$hoh{$id} = \%hash;

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

于 2013-07-19T20:04:19.607 回答
2

要获得对哈希变量的引用,您需要使用\%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]}, ...)通过分配给它,我将第一个值分配给splitto $hash{$columns[0]},第二个值分配给$hash{$columns[1]},依此类推。它与您的循环完全相同while ... $iter,只是没有显式循环(并且它不提取$id.

无需在循环内部进行$k比较'Id';只需将其作为普通字段存储在哈希中,然后使用$hash{Id}. (旁白:是您的列标题Id还是id?您Id在循环中使用,但id在预期输出中使用。)

如果您不想将Id字段保留在各个条目中,则可以使用delete(从哈希中删除键并返回值):

$hoh{delete $hash{Id}} = \%hash;
于 2013-07-19T21:16:23.837 回答
1

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

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

我还建议您查看 CPAN。这是可以执行许多不同任务的各种 Perl 模块的存档。查看Text::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;
于 2013-07-19T21:20:06.483 回答
0

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

$hoh{$id} = \%hash;

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

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

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

于 2013-07-19T23:34:11.993 回答