Arrays perl从2个数组中提取公共元素(fastq文件中的公共序列)

Arrays perl从2个数组中提取公共元素(fastq文件中的公共序列),arrays,perl,bioinformatics,sequences,fastq,Arrays,Perl,Bioinformatics,Sequences,Fastq,我有两个文件(成对的)从同一个有机体(文件R1.fastq和文件R2.fastq)读取fastq格式的数据。我想使用bwa和samtools(生物信息学)确定深度覆盖率,为此我需要两个文件具有相同的读取次数,相同的名称(文件1:@XX00341:4450:6341 1:N:0:aacgtaa+TTGCAATT和文件2:@XX00341:4450:6341 2:N:0:aacgtaa+TTGCAATT),在两个文件中的顺序相同,问题是,两个文件都有空读取(每个文件对应的读取,可能在一个文件中为空,

我有两个文件(成对的)从同一个有机体(文件R1.fastq和文件R2.fastq)读取fastq格式的数据。我想使用bwa和samtools(生物信息学)确定深度覆盖率,为此我需要两个文件具有相同的读取次数,相同的名称(文件1:@XX00341:4450:6341 1:N:0:aacgtaa+TTGCAATT和文件2:@XX00341:4450:6341 2:N:0:aacgtaa+TTGCAATT),在两个文件中的顺序相同,问题是,两个文件都有空读取(每个文件对应的读取,可能在一个文件中为空,但在另一个文件中为空!!!!),如果我尝试使用bwa运行它,它会由于空序列而失败

因此,我试图制作一个perl脚本来提取两个文件中具有相同名称和顺序的非空读取

这是fastq文件的格式(每次读取有4行:名称(@XX00341:19:000H27K25:1:11101:4450:6341 1:N…)、顺序(gaggtgggttgtcacccc…)、Q_头(+)和质量(fffffffffffffffff…)

文件_r1.fastq(以=..1:N:0:aacgtaa+TTGCAATT为特征)

文件_r2.fastq(以=..2:N:0:aacgtaa+TTGCAATT为特征)

在这种情况下,文件_1.fastq(@XX00341:10259:6342 1:N…)中的一次读取为空,第二行和第四行为空(序列和质量),但文件_2.fastq(@XX00341:10259:6342 2:N…)中不为空;在本例中,两个序列(每个文件中的4行)必须省略

这是我试图完成的代码:

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;

my ($fastQ_R1, $fastQ_R2);
      GetOptions (
            'R1|r1=s'   =>\$fastQ_R1,
            'R2|r2=s'   =>\$fastQ_R2,

      );

    sub extract_list {
        my ($file_in) = @_;
        open FILE, '<', $file_in or die "cant open the $file_in\n";

        my (@elements, @list, @seq);
        while(
            defined(my $head    =   <FILE>) &&   # 1 line
            defined(my $seq     =   <FILE>) &&   # 2 line
            defined(my $qhead   =   <FILE>) &&   # 3 line
            defined(my $quality =   <FILE>)      # 4 line
        ){
            if ($seq=~ m/^$/g){
                next;
            }
            else {  push @seq, $head;   }
         }
        close FILE;
        foreach (@seq){
            chomp;
            @elements = split '\s', $_;
                push @list, $elements[0]; # split to eliminate 1:N... (file_1) and 2:N... (file_2)
        }
        return @list;
    }

    my @list_R1 = extract_list ($fastQ_R1);

    my @list_R2 = extract_list  ($fastQ_R2);
@清单2=

@XX00341:4450:6341   
@XX00341:14420:6341   
@XX00341:6685:6342   
@XX00341:4051:6343   
@XX00341:12307:6344   
@XX00341:24250:6345
@XX00341:4450:6341   
@XX00341:14420:6341   
@XX00341:10259:6342
@XX00341:6685:6342   
@XX00341:4051:6343   
@XX00341:12307:6344   
@XX00341:24250:6345
@公共元素=

@XX00341:4450:6341   
@XX00341:14420:6341   
@XX00341:6685:6342   
@XX00341:4051:6343   
@XX00341:12307:6344   
@XX00341:24250:6345
因此,新数组(@common_elemnts)将用于搜索和提取每个文件的公共读取(4行),并将提供两个输出文件:files_R1_common.fastq(从文件_R1.fastq获得)和files_R2_common.fastq(从文件_R2.fastq获得)

如有任何建议,将不胜感激!!!!
非常感谢

您最好使用哈希映射检查列表中是否存在项。
构造公共哈希映射:

my %list1_map = map { $_, 1 } @list_R1;
my %common_map = map { $list1_map{$_} ? ($_, 1) : () )} @list_R2;
然后处理您的列表:

for my $item(@list_R1) {
if (defined ($common_map{$item})) {
    # ... process ...       
}

在下面的解决方案中,我将FASTQ解析移到了一个单独的类中,该类将从文件中读取4行,并返回一个代表一条记录的id、hdr、seq和qual的hashref。我将编写这个类作为一个练习。这样做使下面的逻辑易于理解。可读性很重要

此代码只需从文件1中保存空序列的ID(即$hdr=~/^@(\S+/)中的$1)。然后读取文件2并输出完整记录,还保存空记录的ID。最后,再次读取文件1并通过删除%筛选哈希所指示的记录来输出完整记录

此解决方案效率低下,因为它会读取文件1两次。原始问题中未提及的是,FASTQ文件通常包含数百万条记录,因此将文件1中所有未筛选的记录保存在%筛选哈希中需要大量RAM,但如果您有大量RAM,您可以根据需要进行更改,但就个人而言,我不会担心about读取文件两次

# SAVE IDS OF EMPTY RECORDS FROM FILE1 IN HASH
my %filter;
my $fq = new Fastq($file1);
while (my $rec = nextSeq($fq))
{
    $rec->{seq} or $filter{$rec->{id}} = undef; # not using value
}

# ADD IDS OF EMPTY RECORDS FROM FILE2 TO HASH AND OUTPUT FILTERED_FILE2
open(my $out, '>', "$file2.filtered") or die($!);
$fq = new Fastq($file2);
while (my $rec = nextSeq($fq) )
{
    if ( $rec->{seq} )
    {
        # READ2 FOR THIS PAIR IS NOT EMPTY
        if ( ! exists($filter{$rec->{id}}) )
        {
             # READ1 FOR THIS PAIR IS ALSO NOT EMPTY
             print $out join("\n", $rec->{hdr}, $rec->{seq}, '+', $rec->{qual}), "\n";
        }
    } else
    {
         # READ2 IS EMPTY, ADD TO FILTERED HASH
         $filtered{$rec->{id}} = undef;
    }
}
close($out);

# OUTPUT FILTERED_FILE1
open($out, '>', "$file1.filtered") or die($!);
$fq = new Fastq($file1);
while (my $rec = nextSeq($fq) )
{
    if ( $rec->{seq} and ! exists($filter{$rec->{id}}) )
    {
         print $out join("\n", $rec->{hdr}, $rec->{seq}, '+', $rec->{qual}), "\n";
    }
}  
close($out);   
for my $item(@list_R1) {
if (defined ($common_map{$item})) {
    # ... process ...       
}
# SAVE IDS OF EMPTY RECORDS FROM FILE1 IN HASH
my %filter;
my $fq = new Fastq($file1);
while (my $rec = nextSeq($fq))
{
    $rec->{seq} or $filter{$rec->{id}} = undef; # not using value
}

# ADD IDS OF EMPTY RECORDS FROM FILE2 TO HASH AND OUTPUT FILTERED_FILE2
open(my $out, '>', "$file2.filtered") or die($!);
$fq = new Fastq($file2);
while (my $rec = nextSeq($fq) )
{
    if ( $rec->{seq} )
    {
        # READ2 FOR THIS PAIR IS NOT EMPTY
        if ( ! exists($filter{$rec->{id}}) )
        {
             # READ1 FOR THIS PAIR IS ALSO NOT EMPTY
             print $out join("\n", $rec->{hdr}, $rec->{seq}, '+', $rec->{qual}), "\n";
        }
    } else
    {
         # READ2 IS EMPTY, ADD TO FILTERED HASH
         $filtered{$rec->{id}} = undef;
    }
}
close($out);

# OUTPUT FILTERED_FILE1
open($out, '>', "$file1.filtered") or die($!);
$fq = new Fastq($file1);
while (my $rec = nextSeq($fq) )
{
    if ( $rec->{seq} and ! exists($filter{$rec->{id}}) )
    {
         print $out join("\n", $rec->{hdr}, $rec->{seq}, '+', $rec->{qual}), "\n";
    }
}  
close($out);