【发布时间】:2018-10-29 10:49:27
【问题描述】:
我正在尝试编写一个脚本,它将数据列从(不是很大).csv 中分离到单独的列表中,以供以后使用Text::CSV_XS 库使用。获取单个列没有问题,但我似乎无法使用 foreach 循环遍历列列表。
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV_XS;
use 5.18.2;
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 });
open my $fh, "<", "/users/whoever/test_csv.csv" or die "$!";
sub column_grabber {
foreach my $column (@_) {
my @data = map { $_->[$column] } @{$csv->getline_all ($fh)};
return @data;
}
}
my @column_numbers = (1,2,3,4);
my @collected_data = column_grabber(@column_numbers);
close $fh or die "$!";
为列列表调用此子例程只给了我预期的列表的第一列,但没有列表中的以下列。一些故障排除表明@_ 看到了我通过的整个列表。
通过省略 return 语句,foreach 循环将遍历 @ids 中传递的所有列,但我没有从 @data 获得任何输出。
我没有考虑到循环中的某些行为吗?也许它与 map() 语句有关?
编辑/解决方案
所以在玩了一段时间并重新思考了一下之后,我已经解决了我的问题。
- 首先,从循环内部打开和关闭文件句柄似乎有 解决了很多头痛。
- 其次,在外部解析
@column_numbers要容易得多 子例程并将标量传递给&column_grabber。这节省了 当我真的不需要时,我不会迷失在参考的海洋中 担心这个小脚本。
所以现在我的功能脚本如下所示:
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV_XS;
use 5.18.2;
sub column_grabber {
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 });
open my $fh, "<", "/users/whoever/test_csv.csv" or die "$!";
my $column = shift @_;
my @data = map { $_->[$column] } @{$csv->getline_all ($fh)};
return @data;
close $fh or die "$!";
}
my @column_numbers = (1,2,3,4);
foreach my $column(@column_numbers){
my @collected_data = &column_grabber($column);
...
}
感谢评论者的意见和帮助。
【问题讨论】:
-
循环内部的函数
returns,在第一次迭代中,所以它永远不会通过除第一个以外的列。另一方面,我建议养成始终将参数解包到函数的习惯,除非您对速度有某种终极需求。 (即便如此,如果归根结底,可能应该再次查看设计。)由于来自调用者的输入在@_中具有别名,因此直接使用时很可能会出现讨厌的错误。另一个好习惯是通过引用传递列表(数组和哈希)(除非它们只是自变量的短集合)。 -
感谢@zdim 的帮助,我会牢记这些建议。