perl - 从文件中获取列名

标签 perl

我的 Perl 脚本中有以下命令:

my @files = `find $basedir/ -type f -iname '$sampleid*.summary.csv'`; #there are multiple summary.csv files in my basedir. I store them in an array
my $summary = `tail -n 1 $files[0]`; #Each summary.csv contains a header line and a line with data. I fetch here the last line.
chomp($summary);
my @sp = split(/,/,$summary); # I split based on ','
my $gender = $sp[11]; # the values from column 11 are stored in $gender
my $qc = $sp[2]; # the values from column 2 are stored in $gender

现在,我遇到的情况是我的 *summary.csv 文件没有相同的列数。它们都有 2 行,其中第一行代表标题。

我现在想要的不是将第 11 列的值存储在性别中,而是将“性别”列的值存储在 $gender 中。

我怎样才能实现这个目标?

第一次尝试解决方案:

my %hash = ();
my $header = `head -n 1 $files[0]`; #reading the header
chomp ($header);
my @colnames = split (/,/,$header);
my $keyfield = $colnames[#here should be the column with the name 'Gender']
push @{ $hash{$keyfield} };
my $gender = $sp[$keyfield]

最佳答案

您必须阅读标题行和数据才能知道哪列包含哪些信息。最简单的方法是编写实际的 Perl 代码,而不是使用各种命令行实用程序。有关该解决方案,请参阅下文。

修复您的解决方案还需要哈希值。您需要首先读取标题行,将标题字段存储在数组中(就像您已经完成的那样),然后读取数据行。数据需要是散列,而不是数组。哈希是键和值的映射。

# read the header and create a list of header fields
my $header = `head -n 1 $files[0]`;
chomp ($header);
my @colnames = split (/,/,$header);

# read the data line
my $summary = `tail -n 1 $files[0]`;
chomp($summary);

my %sp; # use a hash for the data, not an array

# use a hash slice to fill in the columns
@sp{@colnames} = split(/,/,$summary);

my $gender = $sp{Gender};

这里最棘手的部分是这一行。

@sp{@colnames} = split(/,/,$summary);

我们已将 %sp 声明为哈希,但现在我们使用 @ sigil 访问它。 。那是因为我们正在采取 a hash slice ,如大括号 {} 所示。我们获取的切片是具有 @colnames 中值的名称的所有元素。有多个值,因此返回值不再是标量(带有 $)。有一个返回值列表,因此印记变为 @。现在我们使用左侧的列表(称为 LVALUE ),并将 split 的结果分配给该列表。


使用现代 Perl 来实现

以下程序将使用 File::Find::Rule 来替换 find 命令,并使用 Text::CSV 来读取 CSV 文件。它会抓取所有文件,然后一次打开一个。将首先读取标题行,并将其输入到 Text::CSV 对象中,以便它可以返回哈希引用,您可以使用该引用按名称访问每个字段。

我以一种只读取每个文件一行的方式编写它,正如您所说每个文件只有两行。您可以轻松地将其扩展为循环。

use strict;
use warnings;
use File::Find::Rule;
use Text::CSV;

my $sampleid;
my $basedir;

my $csv = Text::CSV->new(
    {
        binary => 1,
        sep    => ',',
    }
) or die "Cannot use CSV: " . Text::CSV->error_diag;

my @files = File::Find::Rule->file()->name("$sampleid*.summary.csv")->in($basedir);

foreach my $file (@files) {
    open my $fh, '<', $file or die "Can't open $file: $!";

    # get the headers
    my @cols = @{ $csv->getline($fh) };
    $csv->column_names(@cols);

    # read the first line
    my $row = $csv->getline_hr($fh);

    # do whatever you you want with the row
    print "$file: ", $row->{gender};
}

请注意,我尚未测试过该程序。

关于perl - 从文件中获取列名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45542989/

相关文章:

linux - 如果没有安装 postgres,我该如何安装 DBD::Pg?

perl - 大致检查 Perl 代码的语法,比 perl -c 快

python - 难以理解如何正确地将 Perl 匹配转换为 Python

mysql - Perl 和 MySQL 插入 XML 字符串导致错误 2006 "server gone away"

perl - 检查静默终端命令写入文件的进度?

perl - Perl 面向对象设计模式

regex - 需要知道几个正则表达式背后的逻辑

Perl - while 循环的意外结果

perl - 当字节存储在 Perl 中的不同变量中时,如何从其字节创建 Unicode 字符?

当键和值都是数组引用时的 Perl 哈希