从CSV文件中搜索并删除列

时间:2013-08-17 15:20:35

标签: arrays perl csv

我正在尝试编写一个子程序,它将在CSV文件中包含两个参数filenamecolumn 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的新手,所以我有点挣扎。

3 个答案:

答案 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
};

旁注: 你真的应该使用strictwarnings;

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方式如何完成这类任务。