我有一个CSV文件,我希望在Perl中变成一个hashrefs数组。这是一个已解决的问题。复杂的是这个文件包含重复的列名,我想映射重复的列名,例如,如果有两列名为'Field1',则返回的哈希有键'Field1_1'和'Field1_2',但是如果只有一个名为'Field3'的列,则返回的哈希中的相应键是'Field3'。
所以对于一个文件:
'Field1','Field2','Field3','Field1','Field4' 'alpha','beta','gamma','delta','kappa'
生成的哈希应该是:
$hash = {
'Field1_1' => 'alpha',
'Field2' => 'beta',
'Field3' => 'gamma',
'Field1_2' => 'delta',
'Field4' => 'kappa',
};
答案 0 :(得分:4)
问题的关键在于如何将增加的数字后缀附加到数组中的重复项。您可以将后缀添加到所有重复项,但是单个传递中的第一个是这样的:
my %seen;
my @header = qw(Field1 Field2 Field3 Field1 Field4);
my @fields = map { $seen{$_}++ > 0 ? $_ . '_' . $seen{$_} : $_ } @header;
Field1
的第一次出现将保持不变,而第二次出现Field1_2
。要将后缀附加到所有重复项(包括第一个),需要多次传递。这是一种方法:
my %seen;
my @header = qw(Field1 Field2 Field3 Field1 Field4);
$seen{$_}++ for @header;
# Filter out non-dupes
for (keys %seen) {
delete $seen{$_} if $seen{$_} <= 1;
}
my @fields;
for (reverse @header) {
if (exists $seen{$_}) {
unshift @fields, $_ . '_' . $seen{$_}--;
}
else {
unshift @fields, $_;
}
}
__END__
Field1_1, Field2, Field3, Field1_2, Field4
使用Text::CSV,您可以使用column_names()
方法指定列名称(惊喜,惊喜)。以下内容使用更简单的单遍方法中的映射列名称将CSV读入hashrefs数组:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Text::CSV;
my $csv = Text::CSV->new({ binary => 1, auto_diag => 1})
or die "Cannot use CSV: " . Text::CSV->error_diag();
open my $fh, '<', 'file.csv' or die $!;
my $header = $csv->getline($fh);
my %seen;
my @fields = map { $seen{$_}++ > 0 ? $_ . '_' . $seen{$_} : $_ } @$header;
$csv->column_names(\@fields);
my $rows = $csv->getline_hr_all($fh);
print Dumper $rows;
close $fh;
$VAR1 = [
{
'Field4' => 'kappa',
'Field2' => 'beta',
'Field1_2' => 'delta',
'Field1' => 'alpha',
'Field3' => 'gamma'
}
];
答案 1 :(得分:1)
ThisSuitIsBlackNot的回答当然是彻底和有帮助的。
那就是说,我想,为了Perl可以像热瑜伽老师一样弯曲桑拿,这表明如果后缀想要附加到所有副本,这个可以在一行中完成,但知道,这很难看:
my @foo = ('123','234','345','123','456', '000', '234', '123');
@foo = map {my $idx = $_; my $val = $foo[$idx]; grep($foo[$_] eq $val, 0..$#foo) > 1 ? $foo[$_]."_".scalar(grep($foo[$_] eq $val, 0..$idx)) : $foo[$_]} 0..$#foo;
print Dumper(\@foo) . "\n";
<强>输出:强>
$VAR1 = [
'123_1',
'234_1',
'345',
'123_2',
'456',
'000',
'234_2',
'123_3'
];