解释

解释

这是我在这个网站上提出的第一个问题,所以如果我解释得不好,请原谅。我也是新手。我研究了一些 perl 和 unix 命令行的东西,但就是不知道如何解决这个问题。

我有 2 个文件 - 文件 A 是主文件,包含 10 多列和大约 15,000 行,文件 B 包含 4 列和大约 1500 行。

我想一次获取文件 B 中的每一行,并将这些列与文件 A 中的相应列进行匹配(这两个文件之间的顺序不同,但列标题相同)。如果文件 A 中文件 B 的所有 4 列都匹配,则从文件 A 中删除整行,并放入新文件(文件 C)中。


例子:

文件A

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 4   57497067    na  no  612 612 DonorAR2
54  Baillie2011 X   154790187   TMLHE   no  612 612 DonorAR2
54  Baillie2011 5   159351203   ADRA1B  no  612 612 DonorAR2
54  Baillie2011 13  79259801    na  no  612 612 DonorAR2
54  Baillie2011 8   4452925 CSMD1   no  610 610 DonorAH

文件B

study_id.x  sample_name chromosome  g_start
Baillie2011 DonorAH 8   4452925
Baillie2011 DonorBC 9   5491376
Baillie2011 DonorAH 8   5829283
Baillie2011 DonorCH 8   5829283

结果:

文件A

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 4   57497067    na  no  612 612 DonorAR2
54  Baillie2011 X   154790187   TMLHE   no  612 612 DonorAR2
54  Baillie2011 5   159351203   ADRA1B  no  612 612 DonorAR2
54  Baillie2011 13  79259801    na  no  612 612 DonorAR2

文件C

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 8   4452925 CSMD1   no  610 610 DonorAH

答案1

perl -MFatal='open,close' -ali -ne '
   if ( @ARGV ) { # FileB readin
      if ( $. == 1 ) { push @names, @F;      }
      else           { push @A, join $/, @F; }
      print;
   } else { # FileA readin
      if ( $. == 1 ) {
         open FILEC, ">", "FileC.out";
         print FILEC $_;
         print;
         @remap =
            map {
               my $n = $names[$_];
               grep { $n eq $F[$_] } 0 .. $#F;
            } 0..$#names;
      } else {
         my $n = join $/, @F[@remap];
         if ( grep { $n eq $_ } @A ) { print FILEC $_; }
         else                        { print;          }
      }
   }
   eof and $. = 0;
   eof() and close FILEC;
' FileB FileA

解释

  • 我们按顺序向 Perl 命令行提供 2 个文件“FileB”和“FileA”。
  • 在读取 FileB 的过程中,我们根据是在第一行还是其他行执行两件事:
    • 对于 FileB 的第一行,我们将 FileB 字段的名称存储到数组中@names
    • 对于其他行,我们使用由默认情况下提供的@A换行符连接的字段填充数组。\n$/RS
    • 在这两种情况下,我们都会将这些行打印到 STDOUT,以便在Perls-i模式下无损地读取 FileB。
  • 现在,当我们读取 FileA 时,在它的第一行打开一个写入文件句柄,FILEC以便我们能够填充该FileC.out文件。
    • 我们打印到 STDOUT,因为我们希望保留 FileB 中的这一行。
    • 我们还打印到文件句柄 FILEC,因为我们希望标头也进入 FileC.out。
    • 现在这是关键的步骤,其中将FileB的字段映射到FileA的字段。
  • 对于 FileA 中的非第一行,我们对这些重新映射的字段与数组中已存储的 FileB 数据执行相等性检查@A
  • 如果找到匹配项,则将此行写入 FileC.out 但不要写入 FileA。如果未找到匹配项,则写入 FileA,但不写入 FileC.out。
  • 在任一文件结束时,我们将行计数器重置$.为 0,以便可以对两个文件执行第一行相等性检查。
  • 在最终的 eof 后(通过 eof() 检测到),我们关闭文件句柄 FILEC。
  • 该模块Fatal.pm加载openclose具有在这些操作上自动退出的功能。

相关内容