我已将最常见的emp表格导出为CSV格式。我想将每个列名称作为哈希键,并将值存储在数组中。
以下是代码
use Data::Dumper;
open($fh,"<EMP.csv");
%hash = ();
local $/= "\n";
while(<$fh>){
@columnNames = split(/,/,$_) if $. ==1;
@columnValues = split(/,/,$_);
push @{hash->{@columnNames}} ,@columnValues;
}
print Dumper(\%hash);
当我尝试打印哈希时,我得到了这个
$VAR1 = {
'8' => [
'"EMPNO"',
'"ENAME"',
'"JOB"',
'"MGR"',
'"HIREDATE"',
'"SAL"',
'"COMM"',
'"DEPTNO"
',
'"7839"',
'"KING"',
'"PRESIDENT"',
'""',
'"11/17/1981"',
'"5000"',
'""',
'"10"
',
但我期待这一点
$VAR1 = { '"EMPNO"'=>[12,3,4,5,6,7,8,9],
'"EMPNAME"'=>["pavan","kumar"...],
};
答案 0 :(得分:5)
您正尝试在推送语句中使用切片,但这不起作用。数组将处于标量上下文中,这就是您看到键8
的原因。您需要循环键以将值推送到数组上。但是,为什么这样呢?
你可以使用Text::CSV
模块,这很简单,可能更合适,假设你有一个真正的csv格式。
use strict;
use warnings;
use Data::Dumper;
use Text::CSV;
my $csv = Text::CSV->new({
binary => 1,
eol => $/,
});
my %data;
open my $fh, "<", "yourfile.csv" or die $!;
$csv->column_names ($csv->getline($fh)); # get header names
while (my $row = $csv->getline_hr($fh)) { # get hashref with values
for my $key (keys %$row) {
push @{$data{$key}}, $row->{$key}; # store values
}
}
print Dumper \%data;
答案 1 :(得分:1)
重写此行
push @{hash->{@columnNames}} ,@columnValues;
为:
foreach my $columnName (@columnNames) {
my $columnValue = shift @columnValues;
push @{ $hash{$columnName} }, $columnValue;
}
答案 2 :(得分:1)
这是你的问题:
push @{hash->{@columnNames}} ,@columnValues;
您尝试将@columnNames
用作哈希中的键。 Perl会在标量上下文中自动获取它,因此,为8
提供键,因为数组中有八个值。
您要做的是将CSV中的第一行(包含列名称)视为特殊行,因为这些行将是您的数组的键。
my @column_names = read_csv_row; #Column names
my %employee_hash;
for my $column ( @column_names ) {
$employee_hash{$column} = [];
}
这将为您提供一个哈希,按列名键入以引用数组。您现在必须读入CSV表的每一行,并将每个字段推送到正确的列散列中;
while ( my @employee_fields = read_csv_row ) { #Your employee record is in @employee
for my $field_num ( 0..$#employee_fields) {
push @{ $employee_hash{$column_names[$field_num] }, $employee_fields[$field_num];
}
}
这样做是从CSV行中取出每个字段并将其推入%employee_hash
中正确的数组引用。我正在利用@column_names
与每行的顺序相同。因此,$column_names[$field_number]
是正确的哈希键,应该对应$employee_fields[$field_num]
。
但是,你在帖子中说的结构可能不是你真正想要的。你想要的是这样的:
%VAR = {
7839 => {
ENAME => "KING",
JOB => "PRESIDENT",
MGR => "",
HIREDATE => "11/17/1981",
SAL => "5000",
COMM => "",
DEPTNO => "10",
}
}
这将按照员工编号键入每个员工,并将所有相关员工字段作为该值的一部分。然后,您可以将员工编号7839的职称称为$employee{7839}->{JOB}
,该员工的姓名为$employee{7839}->{NAME}
。这样,每个员工的所有信息都集中在一个记录中:
use warnings;
use strict;
use Data::Dumper;
use feature qw(say);
my @column_names = read_csv_row(); #Column name
my %employee_hash;
while ( my @minion_fields = read_csv_row() ) { #Your employee record is in @employee
my %minion_hash;
my $minion_number = $minion_fields[0];
for my $field_num ( 1..$#minion_fields) {
$minion_hash{ $column_names[$field_num] } = $minion_fields[$field_num];
}
$employee_hash{$minion_number} = \%minion_hash;
}
sub read_csv_row {
my $row = <DATA> or return;
chomp $row;
return split /,\s+/, $row;
}
say Dumper \%employee_hash;
__DATA__
empno, name, job, mgr, hiredate, sal, comm, deptno
7839, king, president, , 11/17/1981, 5000, , 10
1234, prince, vice-president, , 10/1/1980, 3000, , 10
顺便说一下,我还没有测试过这段代码。 (我现在就这样做,并进行必要的更正。)您可能想要使用Text::CSV
,这将是一种更好的CSV文件阅读方式,甚至可以帮助您创建这些结构(我很久没有使用它,所以我不记得它做的一切)。但是,我相信你会发现你的员工结构是哈希的哈希值,其初始哈希值是由员工编号键入的,而字段键入的子哈希比数组的哈希要好得多。