识别并插入缺失的行

时间:2016-08-09 19:22:06

标签: perl

从制表符分隔的文本(5列)文件中填充数组,该文件有时会丢失行。我需要识别并插入缺失的行。插入字符串"找到空白行"已经足够了。

以下是来自文件的数据示例:

chr1:11174372   MTOR    42939   42939   7
chr1:65310459   JAK1    1948    1948    3

我创建了一个元素数组,用于标识文件中应存在的每一行的第二列,按行每个行的顺序排列。但是,我不知道如何从这里继续,因为我无法在服务器上安装任何Perl模块(例如Arrays :: Utils)。

比较数组是否是解决此问题的正确方法?也许有一个简单的解决方案,不需要安装任何CPAN模块?谢谢你的帮助。

#!perl
use strict;
use warnings;
use File::Basename;
#use Arrays::Utils;

opendir my $dir, "/data/test_all_runs" or die "Cannot open directory: $!";
my @run_folder = readdir $dir;
closedir $dir;

my $run_folder = pop @run_folder; print "The folder is".$run_folder."\n";

my $home="/data/";                                                     

my $CNV_file = $home."test_all_runs/".$run_folder."/CNV.txt";

my @CNVarray;
open(TXT2, "$CNV_file");
        while (<TXT2>){
            push (@CNVarray, $_);   
            }
    close(TXT2);

foreach (@CNVarray){
    chop($_);
}

my @array1 = map { $_->[1] } @CNVarray;

my @array2 = qw(MTOR JAK1 NRAS DDR2 MYCN ALK IDH1 ERBB4 RAF1 CTNNB1 PIK3CA DCUN1D1 FGFR3 PDGFRA KIT APC FGFR4 ROS1 ESR1 EGFR CDK6 MET SMO BRAF FGFR1 MYC JAK2 GNAQ RET FGFR2 HRAS CCND1 BIRC2 KRAS ERBB3 CDK4 AKT1 MAP2K1 IDH2 NF1 ERBB2 BRCA1 GNA11 MAP2K2 JAK3 AR MED12);

    my %array1_hash;
    my %array2_hash;

    # Create a hash entry for each element in @array1
    for my $element ( @array1 ) {
       $array1_hash{$element} = @array1;
    }

    # Same for @array2: This time, use map instead of a loop
    map { $array_2{$_} = 1 } @array2;

    for my $entry ( @array2 ) {

            if ( not $array1_hash{$entry} ) {
                return 1;  #Entry in @array2 but not @array1: Differ

        }else {
           return 0;   #Arrays contain the same elements
        }
    #if ( keys %array_hash1 != keys %array_hash2 ) {
       #return 1;   #Arrays differ
    }

2 个答案:

答案 0 :(得分:2)

注意最后会达到最佳版本。这是几行代码。

如果我做得对,你有一个单独的关键词参考列表,需要在一行的第二个字段中,按行顺序排列。查找跳过行的一种方法是遍历两个列表。

这种方法可能挑剔且容易出错,但是每次通过从参考列表中删除前面的元素可以使这更容易。然后,您始终需要将当前行与参考列表中的第一个元素进行比较。这是基本逻辑,下面是更好的版本。

use warnings;
use strict;

open my $cnv_fh, '<', $CNV_file or die "Can't open $CNV_file: $!";
my @CNVarray = <$cnv_fh>;
close $cnv_fh;
# chomp(@CNVarray);

my @ref_list = qw(MTOR JAK1 ...);

foreach my $line (@CNVarray) 
{
    if ( (split /\t/, $line)[1] eq $ref_list[0] ) {  # good row
        shift @ref_list;
        print $line, "\n";
    }
    else {
        shift @ref_list;
        print "blank row found\n";
        while ( (split /\t/, $line)[1] ne $ref_list[0] ) {
            # multiple missing rows? keep going through the reference list
            shift @ref_list;
            print "blank row found\n";
    }
 }
 # We are done with the array, but are there more reference items?
 print "blank row found\n" for @ref_list;

需要while循环,因为可能缺少多行(在一行中),因此我们需要到达与当前行匹配的引用列表中的位置。关于代码的一些注释。

  • 列表上下文中的文件句柄读取<...>返回包含资源中所有行的列表。
  • 原始代码中的chop删除了最后一个字符,可能不是您想要的。 chomp删除了新行(或真正的$/)。

使用输入文件(注释空格而非标签)对引用列表qw(AA BB CC DD EE)进行了测试

1 AA first
2 BB more
5 EE last

要使用此功能进行测试,请将/\t/更改为/\s/(这样也适用于标签页)。它打印

1 AA first
2 BB more
blank row found
blank row found
5 EE last

如果在@ref_listFF等)中添加了更多元素,则会打印更多blank ...行。

上面的代码可以简化。行也收集在一个数组中,然后打印到一个新文件。

use warnings;
use strict;

open my $cnv_fh, '<', $CNV_file or die "Can't open $CNV_file: $!";
my @CNVarray = <$cnv_fh>;
close $cnv_fh;
chomp(@CNVarray);

my @ref_list = qw(MTOR JAK1 ...);
my @new_lines;

foreach my $line (@CNVarray) 
{
    while ( (split /\t/, $line)[1] ne $ref_list[0] ) {
        shift @ref_list;
        push @new_lines, 'blank row found';
        print "blank row found\n";
    }
    shift @ref_list;
    push @new_lines, $line;         
    print $line, "\n";
}
# There may be more items remaining on the reference list
for (@ref_list) {
    push @new_lines, 'blank row found';
    print "blank row found\n" 
}


my $filled_file = 'skipped_rows_added.txt';
open my $out_fh, '>', $filled_file  or die "Can't open $filled_file: $!";
print $out_fh "$_\n" for @new_lines;
close $out_fh;

这与上面的测试输入的行为方式相同。它可以进一步简化

foreach my $line (@CNVarray) 
{
    while ( (split /\t/, $line)[1] ne shift @ref_list ) {
        print "blank row found\n";
    }
    print $line, "\n";
}

shift返回已删除的元素,这是需要测试的元素。

关于代码更新后split语法的说明("\t"更改为/\t/)。

split /$patt/, $str方式调用时,$patt用作正则表达式,但有一些非常小的差异。因此,对于/\s/,字符串在白色空间上分割,正如在regex中所理解的那样,因此包括选项卡。

使用双引号"..."代替/.../,内部的内容首先进行插值,这可能会导致意外,特别是对于转义。 (除非它被用作m"...",在这种情况下它只是一个正则表达式,"是分隔符。)

在上面的标签代码中,可以使用/\t/"\t"'\t'(或/\s/,其中包括其他类型的空间)。 "\t"已更改为/\t/,我认为这更好,更清晰(正则表达式,没有问题)。感谢Borodin进行早期编辑和评论。

答案 1 :(得分:1)

我会写这个

输入文件被读入哈希,由第二列的值键入。然后回读散列并以指定的键序列打印

大多数代码都是查找输入文件并设置键序列。该计划的核心只有三行代码

use strict;
use warnings 'all';

use File::Spec::Functions 'catfile';

my $home = '/data';

my @run_folder = grep -f, glob catfile($home, 'test_all_runs', '*', 'CNV.txt');
die "No CNV file found" unless @run_folder;

my $cnv_file = $run_folder[-1];
print "The file is $cnv_file\n\n";

my @sequence = qw/
    MTOR    JAK1    NRAS    DDR2    MYCN    ALK
    IDH1    ERBB4   RAF1    CTNNB1  PIK3CA  DCUN1D1
    FGFR3   PDGFRA  KIT     APC     FGFR4   ROS1
    ESR1    EGFR    CDK6    MET     SMO     BRAF
    FGFR1   MYC     JAK2    GNAQ    RET     FGFR2
    HRAS    CCND1   BIRC2   KRAS    ERBB3   CDK4
    AKT1    MAP2K1  IDH2    NF1     ERBB2   BRCA1
    GNA11   MAP2K2  JAK3    AR      MED12
/;

open my $fh, '<', $cnv_file or die qq{Unable to open "$cnv_file" for input: $!};

my %data;
$data{ (split)[1] } = $_ while <$fh>;

print $data{$_} // "no data for $_\n" for @sequence;

输出

The file is /data/test_all_runs/XXX/CNV.txt

chr1:11174372   MTOR    42939   42939   7
chr1:65310459   JAK1    1948    1948    3
no data for NRAS
no data for DDR2
no data for MYCN
no data for ALK
no data for IDH1
no data for ERBB4
no data for RAF1
no data for CTNNB1
no data for PIK3CA
no data for DCUN1D1
no data for FGFR3
no data for PDGFRA
no data for KIT
no data for APC
no data for FGFR4
no data for ROS1
no data for ESR1
no data for EGFR
no data for CDK6
no data for MET
no data for SMO
no data for BRAF
no data for FGFR1
no data for MYC
no data for JAK2
no data for GNAQ
no data for RET
no data for FGFR2
no data for HRAS
no data for CCND1
no data for BIRC2
no data for KRAS
no data for ERBB3
no data for CDK4
no data for AKT1
no data for MAP2K1
no data for IDH2
no data for NF1
no data for ERBB2
no data for BRCA1
no data for GNA11
no data for MAP2K2
no data for JAK3
no data for AR
no data for MED12