Perl - 计算文件每行中的变量

时间:2012-12-04 11:35:33

标签: perl variables hash count

我有两个文件:allinfo.txt和chr1.txt。

allinfo.txt看起来像

rs4477212    1   82154       A   A
rs3094315    1   752566      G   A 
rs3131972    1   752721      A   G 
rs12124819   1   776546      A   G  

而chr1.txt看起来像

rs4477212    1   82154       A  A
rs3094315    1   752566      A  G
rs3131972    1   752721      A  G
rs12124819   1   776546      A  A

尽管这两个文件看起来非常相似,但它们所携带的信息实际上却截然不同。但是,基本上,我想要做的是:对于allinfo中的每一行,我想取第四列中的字母并在chr1中搜索该字母的相应行并计算它出现的次数。如果它出现两次,我想将1 0 0(三列)附加到allinfo的那一行。如果它只出现一次,我想将0 1 0(再次,三列)附加到allinfo的那一行。如果它没有出现,我想将0 0 1附加到allinfo的那一行。如果我真的可以这样做,我应该得到以下结果:

rs4477212    1   82154       A   A  1 0 0
rs3094315    1   752566      G   A  0 1 0
rs3131972    1   752721      A   G  0 1 0
rs12124819   1   776546      A   G  1 0 0

首先请注意,前五列正是allinfo.txt文件中已有的列。由于chr1在第一行中有两个A,所以我必须将1 0 0连接到第一行。查看第二行,因为chr1在第二行中只有一个G,所以我必须将0 1 0连接到第二行。其余部分也是如此。

到目前为止我的代码:

#!/usr/bin/perl

use strict;
use warnings;

use File::Slurp;

use Data::Dumper;

open(FILE, '<', 'test_chr1_allinfo.txt');

my @array = read_file('test_chr1.txt');

my %hash;
while (<FILE>)
{
    (my $rs, my $chr, my $bp, my $a0, my $a1) = split(" ");
    my $line = $.;
    my $allele = $a0;
    $hash{$line} = $allele;
}   


foreach my $item (keys %hash)
{
...
}

正如你所知,我不确定我将如何进行foreach循环。我通过将密钥作为该行中第一个等位基因的行号并将其分配给该行中列出的第一个等位基因来构建我的哈希。然后我将运行我的哈希并为每个项目查看chr1中的特定行并计算等位基因出现的次数。根据这个数字,我可以找出将1放在我需要的三列中的位置。但是,我不知道如何对此进行编码,因为我刚开始为这个项目学习Perl。有人有什么想法吗?

我遇到的另一个问题是:当我打印我的哈希所以我可以看到它里面有什么,为什么它都混乱了?根据我的构造方式,我希望它看起来像

1 => A
2 => G
3 => A
4 => A

然而,我得到了像

这样的东西
4 => A
2 => G
3 => A
1 => A

为什么会这样?

提前感谢任何建议/建议/帮助!

3 个答案:

答案 0 :(得分:2)

此代码符合您的要求。请注意,仅使用最后一列,因为其余列对于任务并不重要。如果你实际上有更多的chr *文件要处理,那么啜饮allinfo.txt会有意义。在这种情况下,您不必打印输出,而是必须记住数组中的三个数字,并在ifs / elses中添加1(例如@counts[$.][0]++)。

#!/usr/bin/perl
use warnings;
use strict;

open my $ALL, '<', 'allinfo.txt' or die $!;
open my $CHR, '<', 'chr1.txt'    or die $!;

while (<$ALL>) {
    chomp;
    my @alleles_all = (split)[-2, -1];
    chomp(my $chr = <$CHR>); # Reads both files line by simultaneously.
    my @alleles_chr = (split ' ', $chr)[-2, -1];
    if ($alleles_chr[0] eq $alleles_chr[1]) {
        if ($alleles_chr[0] eq $alleles_all[0]) {
            print "$_\t1\t0\t0\n";
        } else {
            print "$_\t0\t0\t1\n";
        }
    } else {
        print "$_\t0\t1\t0\n";
    }
}

答案 1 :(得分:0)

这样就可以了解

use strict;
use warnings;

open my $all, '<', 'allinfo.txt' or die $!;
open my $chr1, '<', 'chr1.txt' or die $!;

while (my $line = <$all>) {

  chomp $line;
  my $f4 = (split ' ', $line)[3];

  my $line2 = <$chr1>;
  my $n = grep $_ eq $f4, (split ' ', $line2)[3, 4];

  my @newline = ($line, 0, 0, 0);
  $newline[-($n+1)] = 1;
  print "@newline\n";
}

<强>输出

rs4477212    1   82154       A   A  1 0 0
rs3094315    1   752566      G   A  0 1 0
rs3131972    1   752721      A   G  0 1 0
rs12124819   1   776546      A   G  1 0 0

答案 2 :(得分:0)

这是另一种选择:

use Modern::Perl;
use File::Slurp qw/read_file/;

my %patterns = ( 0 => "0\t0\t1", 1 => "0\t1\t0", 2 => "1\t0\t0" );

chomp( my @allinfo = read_file 'allinfo.txt' );
my @chr1 = read_file 'chr1.txt';

for my $i ( 0 .. $#allinfo ) {
    my $allinfoCol3 = ( split ' ', $allinfo[$i] )[3];
    my ($chr1Cols) = $chr1[$i] =~ /(\S+\s+\S+)$/;
    my $count = () = $chr1Cols =~ /$allinfoCol3/g;
    say "$allinfo[$i]\t$patterns{$count}";
}

输出:

rs4477212    1   82154       A   A  1   0   0
rs3094315    1   752566      G   A  0   1   0
rs3131972    1   752721      A   G  0   1   0
rs12124819   1   776546      A   G  1   0   0