我是使用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
的副本,速度较慢,但对其进行的任何后续更改都不会影响您存储的内容。