我正在尝试编写一个子程序,它将在CSV文件中包含两个参数filename
和column name
。子例程将搜索第二个参数(列名称)并从CSV文件中删除该列(或列),然后返回删除了参数的CSV文件。
我觉得我已经完成了这个子的前半部分(打开文件,检索标题和值)但我似乎无法找到一种方法来搜索CSV文件以查找用户输入的字符串并删除整个列。有任何想法吗?这是我到目前为止所拥有的。
sub remove_columns {
my @Para = @_;
my $args = @Para;
die "Insufficent arguments\n" if ($nargs < 2);
open file, $file
$header = <file>;
chomp $header;
my @hdr = split ',',$header;
while (my $line = <file>){
chomp $line;
my @vals = split ',',$line;
#hash that will allow me to access column name and values quickly
my %h;
for (my $i=0; $i<=$#hdr;$i++){
$h{$hdr[$i]}=$i;
}
....
}
这是搜索和删除的地方。我一直在考虑如何解决这个问题;我将要修改的CSV文件将是巨大的,因此速度是一个因素,但我似乎无法想到一个好的方法来解决这个问题。我是Perl的新手,所以我有点挣扎。
答案 0 :(得分:1)
以下是一些有希望让你前进的提示。
要删除数组位置$index
处的数组元素,请使用:
splice @array,$index,1 ;
由于速度是一个问题,你可能想要在开始时构造一个列数列,然后循环数组的元素
for my $index (@indices) {
splice @array,$index,1 ;
}
(这种方式比for (my $i=0; $i<=$#hdr;$i++)
类型循环更加惯用Perl)
需要考虑的另一件事 - CSV格式非常复杂。您的数据可能会在,
内包含" "
的数据,例如
1,"column with a , in it"
我会考虑使用类似Text::CSV
的内容答案 1 :(得分:1)
你应该朝着Text::CSV
的方向看或者你可以这样做:
my $colnum;
my @columns = split(/,/, <$file>);
for(my $i = 0; $i < scalar(@columns); $i++) {
if($columns[$i] =~ /^$unwanted_column_name$/) {
$colnum = $i;
last;
};
};
while(<$file>) {
my @row = split(/,/, $_);
splice(@row, $colnum, 1);
#do something with resulting array @row
};
旁注:
你真的应该使用strict
和warnings
;
split(/,/, <$file>);
不适用于所有CSV文件
答案 2 :(得分:1)
如何从数组中删除一些列有一种优雅的方法。如果我要在数组@cols
中删除列,并在@headers
中添加标题,我可以使索引数组保留:
my %to_delete;
@to_delete{@cols} = ();
my @idxs = grep !exists $to_delete{$headers[$_]}, 0 .. $#headers;
然后很容易制作新标题
@headers[@idxs]
以及读取列的新行
@columns[@idxs]
例如,可以使用相同的方法来重新排列数组。它是非常快速和非常惯用的Perl方式如何完成这类任务。