逐行比较仅返回每隔一行

时间:2014-09-04 14:13:49

标签: perl

所以我尝试编写一个脚本,将一个文件的每一行与其对应的文件行2(文件1的第1行,文件2的第1行等)进行比较,更改文件1的内容以特定的方式,然后返回此行。到目前为止我编译的代码是这样的:

#!/usr/bin/perl
# alleles.pl
use strict; use warnings;
use List::MoreUtils qw(uniq);

open my $AL, '<', shift or die $!;
open my $HMP, '<', shift or die $!;

<$AL>; # skip header
print scalar <$HMP>; # print header

while (<$AL>, <$HMP>) {
  my @HMP_columns = split (/\t/, <$HMP>);
  my @AL_columns = split (/\t/, <$AL>);
  shift @AL_columns for 0..4;
  my @uniq_AL_columns = uniq(@AL_columns); # only keep unique values in new array
  for (my $i = 11; $i < scalar(@HMP_columns); $i++) { # for every column (starting from column 12)
    if ($HMP_columns[$i] == "1") {$HMP_columns[$i] = $uniq_AL_columns[0]}
    elsif ($HMP_columns[$i] == "2") {$HMP_columns[$i] = $uniq_AL_columns[1]}
    elsif ($HMP_columns[$i] == "3") {$HMP_columns[$i] = $uniq_AL_columns[2]}
    elsif ($HMP_columns[$i] == "4") {$HMP_columns[$i] = $uniq_AL_columns[3]}
    elsif ($HMP_columns[$i] == "5") {$HMP_columns[$i] = $uniq_AL_columns[4]}
    elsif ($HMP_columns[$i] == "6") {$HMP_columns[$i] = $uniq_AL_columns[5]}
    elsif ($HMP_columns[$i] == "7") {$HMP_columns[$i] = $uniq_AL_columns[6]}
    elsif ($HMP_columns[$i] == "8") {$HMP_columns[$i] = $uniq_AL_columns[7]}
    elsif ($HMP_columns[$i] == "9") {$HMP_columns[$i] = $uniq_AL_columns[8]}
  } 
  my $joined_HMP = join ("\t", @HMP_columns); # get back to tab separated lines
  print "$joined_HMP\n";
}

行的格式化工作方式与我希望它的工作方式相同,但是,脚本似乎只对输入的每个第二行起作用,或者至少只返回第二行。我试图以许多不同的方式启动while循环,并尝试了很多其他的东西,比如在while循环之外启动数组,但没有任何作用。任何人都可以告诉我脚本中哪里出错了? (顺便说一下,我知道风格并不漂亮,所以如果你们有任何关于如何使这个脚本更紧凑的建议,请随意这样做!毕竟我想学习。)

3 个答案:

答案 0 :(得分:2)

在每个循环中,您将从每个文件中读取两次。一旦进入while条件,一次进入while body。

将以下行替换为:

use IO::Handle;
while (!($HMP->eof() or $AL->eof()) {

如果任一文件到达结束,这将导致while条件失败。 如果文件可能有不同的长度,你可以检查在while循环后哪一个没有达到eof。

答案 1 :(得分:1)

一些快速提示:

每当你有非常相似的重复代码行时,它就是一个标志,可能有一种更经济的方式来做事。例如,此代码:

for (my $i = 11; $i < scalar(@HMP_columns); $i++) { # for every column (starting from column 12)
    if ($HMP_columns[$i] == "1") {$HMP_columns[$i] = $uniq_AL_columns[0]}
    elsif ($HMP_columns[$i] == "2") {$HMP_columns[$i] = $uniq_AL_columns[1]}
    elsif ($HMP_columns[$i] == "3") {$HMP_columns[$i] = $uniq_AL_columns[2]}
    elsif ($HMP_columns[$i] == "4") {$HMP_columns[$i] = $uniq_AL_columns[3]}
    elsif ($HMP_columns[$i] == "5") {$HMP_columns[$i] = $uniq_AL_columns[4]}
    elsif ($HMP_columns[$i] == "6") {$HMP_columns[$i] = $uniq_AL_columns[5]}
    elsif ($HMP_columns[$i] == "7") {$HMP_columns[$i] = $uniq_AL_columns[6]}
    elsif ($HMP_columns[$i] == "8") {$HMP_columns[$i] = $uniq_AL_columns[7]}
    elsif ($HMP_columns[$i] == "9") {$HMP_columns[$i] = $uniq_AL_columns[8]}
}

可以重构 - $HMP_columns[$i]的新值为$uniq_AL_columns[ $HMP_columns[$i-1] ],因此可以将整个块重写为

for (my $i = 11; $i < scalar(@HMP_columns); $i++) {
    $HMP_columns[$i] = $uniq_AL_columns[$HMP_columns[$i-1]];
}

如果你正在处理数组,那么splice function对于进行各种操作非常方便 - 从数组中删除元素,用其他元素替换它们,等等。 shift @AL_columns for 0..4可以写成splice(@AL_columns, 0, 5);(即从元素0开始从@AL_columns中删除5个元素)。

对于任何perl工作,在您开发脚本时编写调试语句和测试确实很有帮助,这样您就可以确定自己知道发生了什么。通过“说”&#39;脚本执行时变量的值可以真正帮助调试过程。一旦代码投入生产使用,&#39;说&#39;语句可以被注释掉,或者您可以使用环境或程序变量来打开和关闭它们 - 例如

say "\$a is $a; \%b is " . Dumper(\%b) if $verbose; ## set a variable 'VERBOSE'

如果您还没有发现Data::Dumper,它将成为您在开发过程中最好的朋友:它允许您检查数据结构和对象的内容,并找出为什么您精心编写的代码不是&#39 ; t应该工作!

Perl测试在SO答案中涉及的问题太大,但请查看perl文档中的TestTest::Simple。在编写脚本时编写测试套件可以节省大量时间 - 而且比以后更容易实现!

答案 2 :(得分:0)

您忽略在while语句中提取的行,并在split中获取另一行。

下面请找到固定代码。当AL有比HNP更多的行时,它不会检测到这种情况。

while (<$HMP>) {
  my @HMP_columns = split (/\t/, $_);
  if( not defined( $_  = <$AL>)) {
     die "HMP longer than AL";
  }
  my @AL_columns = split (/\t/, $_);