Perl - >在数组哈希散列中比较数组

时间:2016-09-30 20:32:15

标签: arrays perl hash hash-of-hashes

我正在研究由同事制作的bash脚本。由于bash中没有多维数据结构,因此处理输入文件有很多变通方法。当我看到他的剧本时,我认为Perl可以更容易地处理它。我认为,在做转换时,我做得不错,但现在我被卡住了。对于那些知道的人,输入文件是变体调用格式(VCF)。基本上是制表符分隔的文本文件,在特定列中包含特定的信息位。这是输入文件的样子:

##fileformat=VCFv4.2
#CHROM  POS ID  REF ALT QUAL    FILTER  INFO    FORMAT  MBWGS139
AF2122_NC002945 1012102 .   A   G   1137.77 .   AC=2;AF=1.00;AN=2   GT:AD:DP:GQ:PL  1/1:0,29:29:87:1166,87,0
AF2122_NC002945 103811  .   C   G   241.84  .   AC=2;AF=1.00;AN=2   GT:AD:DP:GQ:PL  1/1:0,6:6:18:270,18,0

我要做的第一件事就是将所有文件信息存储在哈希中。通过逐行循环每个文件,多个文件(或样本)都集成在该“主”散列中。主哈希的构造如下:

push(@{ $vcfs{$sample}{$CHROM}{$POS} }, $ID, $REF, $ALT, $QUAL, $FILTER, $INFO, $FORMAT, $SAMPLE);

然后我需要过滤掉“坏”的位置。我会在这里跳过这段代码,但是我保留的信息存储在一个新的哈希中,这个哈希就是这样创建的:

push ( @{ $fastas{$sample}{$chrom}{$pos} }, $allele);

让我们说$ allele = $ ALT(但这有点复杂)。所以在%fasta里面看起来像这样:

Sample1
    chrom1
        pos1 = A
        pos2 = T
    chrom2
        pos1 = A
        pos2 = G
Sample2
    chrom1
        pos1 = C
        pos2 = T
    chrom2
        pos1 = A
        pos2 = G

看到这就像我使用Data :: Dumper打印它一样......你也可以看到,对于那部分代码,我抛弃了一堆信息。

最后一个过滤步骤是去除特定位置上所有样品共有的“等位基因”。在前面的例子中,只保留了chrom的pos1。最终的哈希看起来像这样:

Sample1
    chrom1
        pos1 = A
Sample2
    chrom1
        pos1 = C

我找到了一种方法,通过抛弃位置信息来做到这一点。我需要保留它。如果有人能帮助我,我真的很感激。如果有帮助,我可以提供我目前的解决方案。

谢谢, 马可

1 个答案:

答案 0 :(得分:0)

我找到了两种获得所需输出的方法。但是,看到只有4个等位基因需要考虑,我想知道在更大的数据集中可能存在一个独特的等位基因。

该解决方案包含%count哈希,可用于查找唯一的等位基因。

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

my (%fastas, %counts);

my ($sample, $chr);
while (<DATA>) {
    if (/^(\S.+)$/) {
        $sample = $1;   
    }
    elsif (/^\t(\S.+)$/) {
        $chr = $1;  
    }
    elsif (/^\t\t(pos\d+)\s=\s([TAGC])$/) {
        my $pos = $1,
        my $allele = $2;
        push @{ $fastas{$sample}{$chr}{$pos} }, $allele;
        $counts{$allele}++; 
    }
    else {
        die "Unknown input line $.: <<$_>>";    
    }
}

for my $sample (keys %fastas) {
    my $chr_ref = $fastas{$sample};

    for my $chr (keys %$chr_ref) {
        my $pos_ref = $chr_ref->{$chr};

        for my $pos (keys %$pos_ref) {
            my $allele_ref = $pos_ref->{$pos};

            for my $allele (@$allele_ref) {
                print "$sample $chr $pos $allele\n"
                    if $counts{$allele} == 1;   
            }
        }
    }   
}

__DATA__
Sample1
    chrom1
        pos1 = A
        pos2 = T
    chrom2
        pos1 = A
        pos2 = G
Sample2
    chrom1
        pos1 = C
        pos2 = T
    chrom2
        pos1 = A
        pos2 = G

第二个解决方案使用Deep::Hash::Utils模块。它通过消除第一个解决方案中的嵌套循环来简化代码。

#!/usr/bin/perl
use strict;
use warnings;
use Deep::Hash::Utils 'reach';

my (%fastas, %counts);

my ($sample, $chr);
while (<DATA>) {
    if (/^(\S.+)$/) {
        $sample = $1;   
    }
    elsif (/^\t(\S.+)$/) {
        $chr = $1;  
    }
    elsif (/^\t\t(pos\d+)\s=\s([TAGC])$/) {
        my $pos = $1,
        my $allele = $2;
        push @{ $fastas{$sample}{$chr}{$pos} }, $allele;
        $counts{$allele}++; 
    }
    else {
        die "Unknown input line $.: <<$_>>";    
    }
}

while (my @list = reach(\%fastas)) {
    my $allele = $list[-1];
    print "@list\n" if $counts{$allele} == 1;
}

__DATA__
Sample1
    chrom1
        pos1 = A
        pos2 = T
    chrom2
        pos1 = A
        pos2 = G
Sample2
    chrom1
        pos1 = C
        pos2 = T
    chrom2
        pos1 = A
        pos2 = G

在您提供的数据集上,两个解决方案都打印为Sample2 chrom1 pos1 C