在perl中构建哈希哈希

时间:2013-07-19 19:53:52

标签: perl hashtable

我是使用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'
                   },
     ........
};

我有限的理解是,当我{%}}插入%hash的引用时?我究竟做错了什么?还有一种更简洁的方法可以将我的列和数据数组用作我的%哈希对象中的键值对吗?

- 提前谢谢, 尼汝

4 个答案:

答案 0 :(得分:2)

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

$hoh{$id} = \%hash;

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

答案 1 :(得分:2)

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

为列分配值的更简洁方法是分配给hash slice,如下所示:

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';只需将其作为普通字段存储在哈希中,然后使用$hash{Id}将其提取出来。 (旁白:您的列标题是Id还是id?您在循环中使用Id,但在预期输出中使用id。)

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

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

答案 2 :(得分:1)

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

其中一个教程是关于Perl references的教程。这有助于澄清您的许多问题并解释有关引用和解除引用的信息。

我还建议您查看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;

答案 3 :(得分:0)

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

$hoh{$id} = \%hash;

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

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

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