将大文件读入Perl数组数组并为不同目的操作输出

时间:2010-06-10 16:06:40

标签: perl arrays sorting

我对Perl相对较新,只使用它将小文件转换成不同的格式并在程序之间提供数据。

现在,我需要加强一点。我有一个长度为5,905行的DNA数据文件,每行有32个字段。这些字段没有任何分隔,并且在行内的长度不同,但每个字段在所有5905行上的大小相同。

我需要将每一行输入到文件中的单独数组中,并将该行中的每个字段存储为其自己的变量。我在存储一行时没有任何问题,但是我在连续存储整个文件时遇到了困难。

这就是我将完整数组的第一行分成单个变量的方法:

my $SampleID = substr("@HorseArray", 0, 7);
my $PopulationID = substr("@HorseArray", 9, 4);
my $Allele1A  = substr("@HorseArray", 14, 3);
my $Allele1B = substr("@HorseArray", 17, 3);
my $Allele2A  = substr("@HorseArray", 21, 3);
my $Allele2B = substr("@HorseArray", 24, 3);

...等

我的问题是:1)我需要将每个5905行存储为单独的数组。 2)我需要能够根据样本ID引用每一行,或者根据种群ID引用一组行并对它们进行排序。

一旦在变量中定义了数据,我就可以对数据进行排序和操作。我只是在构造一个包含这些字段的多维数组时遇到了麻烦,所以我可以随意引用每一行。任何帮助或方向都非常感谢。我已经在这里倾听了Q& A部分,但还没有找到我的问题的答案。

3 个答案:

答案 0 :(得分:3)

将每一行存储在自己的数组中。您需要构建一个数据结构。首先阅读以下教程形式perldoc:

这是一些入门代码:

use strict;
use warnings;

# Array of data samples. We could use a hash as well; which is better 
# depends on how you want to use the data.
my @sample;

while (my $line = <DATA>) {
    chomp $line;

    # Parse the input line
    my ($sample_id, $population_id, $rest) = split(/\s+/, $line, 3);

    # extract A/B allele pairs
    my @pairs;
    while ($rest =~ /(\d{1,3})(\d{3})|(\d{1,3}) (\d{1,2})/g) {
        push @pairs, {
            A => defined $1 ? $1 : $3,
            B => defined $2 ? $2 : $4,
        };
    }

    # Add this sample to the list of samples. Store it as a hashref so
    # we can access attributes by name
    push @sample, {
        sample     => $sample_id,
        population => $population_id,
        alleles    => \@pairs,
    };
}


# Print out all the values of alleles 2A and 2B for the samples in
# population py18. Note that array indexing starts at 0, so allele 2
# is at index 1.
foreach my $sample (grep { $_->{population} eq 'py18' } @sample) {
    printf("%s: %d / %d\n",
        $sample->{sample},
        $sample->{alleles}[1]{A},
        $sample->{alleles}[1]{B},
    );
}

__DATA__
00292-97 py17 97101 129129 152164 177177 100100 134136 163165 240246 105109 124124 166166 292292 000000 000000 000000
00293-97 py18 89 97 129139 148154 179179 84 90 132134 167169 222222 105105 126128 164170 284292 000000 000000 000000
00294-97 py17 91 97 129133 152154 177183 100100 134140 161163 240240 103105 120128 164166 290292 000000 000000 000000
00295-97 py18 97 97 131133 148162 177179 84100 132134 161167 240252 111111 124128 164166 284290 000000 000000 000000

答案 1 :(得分:2)

我首先循环遍历这些行并将每个字段解析为字段的哈希值,然后我会为每个索引构建一个哈希值。

my %by_sample_id;           # this will be a hash of hashes
my %by_population_id;       # a hash of lists of hashes
foreach (<FILEHANDLE>) {
    chomp;  # remove newline
    my %h;  # new hash
    $h{SampleID} = substr($_, 0, 7);
    $h{PopulationID} = substr($_, 9, 4);
    # etc...

    $by_sample_id{ $h{SampleID} } = \%h;   # a reference to %h
    push @{$by_population_id{ $h{PopulationID} }}, \%h;  # pushes hashref onto list
}

然后,您可以使用任一索引来访问您感兴趣的数据:

say "Allele1A for sample 123123: ", $by_sample_id{123123}->{Allele1A};
say "all the Allele1A values for population 432432: ", 
     join(", ", map {$_->{Allele1A}} @{$by_population_id{432432}});

答案 2 :(得分:1)

我将假设这不是一次性的计划,所以我的方法会略有不同。 我做了大量的数据混合,过了一段时间,我厌倦了编写针对数据结构的查询。

所以 -

我会将数据提供给SQLite数据库(或其他sql DB),然后使用Perl DBI编写Perl查询。这使得复杂性远远超过了一个简单的“解析和破解”,但是在您编写了几个脚本对同一数据进行查询之后,很明显这是一个痛苦,必须有一个更好的方式

您将拥有与此类似的架构 create table brians_awesome_data (id integer, population_id varchar(32), chunk1 integer, chunk2 integer...);

然后,在你使用了一些mobrule和Michael的优秀解析之后,你就会循环并执行一些INSERT IN到你的awesome_data表。

然后,您可以为您的SQL程序使用CLI并执行“select ... where ...”查询以快速获取所需的数据。

或者,如果它更具分析性/管道性,您可以使用DBI Perl编写脚本并将数据导入分析例程。

相信我,这是比一遍又一遍地对数据结构编写查询更好的方法。