【问题标题】:Unable to read multiple columns from a .csv using Text::CSV_XS in Perl无法在 Perl 中使用 Text::CSV_XS 从 .csv 读取多列
【发布时间】: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 要容易得多 子例程并将标量传递给&amp;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 的帮助,我会牢记这些建议。

标签: perl csv


【解决方案1】:

请记住,@data(在此重命名为@rows$rows)的每个元素都应该是对选定字段数组的引用。

my @rows;
while ( my $row = $csv->getline($fh) ) {
   push @rows, [ @{ $row }[@column_numbers] ];
}

my $rows = $csv->getline_all($fh);
@_ = @{ $_ }[@column_numbers] for @$rows;

my @rows = map { [ @{ $_ }[@column_numbers] ] } @{ $csv->getline_all($fh) };

【讨论】:

  • 您的代码对我有所帮助,而且我是第一次使用参考资料。我遇到的唯一问题是从第一个代码示例中取消引用 @rows。我遇到一个错误,告诉我不能将字符串用作数组引用。我应该做一些不同的事情来从@rows 取回我的数据吗?同样,这是我第一次使用参考文献,所以我可能会遗漏一些重要的东西。
  • 嗯?无法取消引用 @rows。它是一个数组,而不是一个引用。 (是一个引用数组,引用是对元素数量与@column_numbers一样多的数组的引用)
猜你喜欢
  • 2013-01-24
  • 2013-05-17
  • 2019-05-17
  • 1970-01-01
  • 1970-01-01
  • 2014-12-10
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
相关资源
最近更新 更多