1

我正在尝试编写一个子例程,它将接受两个参数,afilenamecolumn nameCSV 文件内部。该子例程将搜索第二个参数(列名)并从 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 的新手,所以我有点挣扎。

4

3 回答 3

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

于 2013-08-17T18:34:13.250 回答
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
};

旁注:你真的应该使用strictand warnings;

split(/,/, <$file>);

不适用于所有 CSV 文件

于 2013-08-17T18:51:35.523 回答
1

有一种优雅的方法可以从数组中删除一些列。如果我在 array 中有要删除的列@cols,并且@headers我可以制作要保留的索引数组:

my %to_delete;
@to_delete{@cols} = ();
my @idxs = grep !exists $to_delete{$headers[$_]}, 0 .. $#headers;

然后很容易制作新的标题

@headers[@idxs]

以及读取列中的新行

@columns[@idxs]

例如,可以使用相同的方法重新排列阵列。如何执行此类任务是非常快速且非常惯用的 Perl 方式。

于 2013-08-17T20:33:00.003 回答