逐行比较只返回每第二行

问题描述:

所以我想写一个脚本比较一个文件的每一行与其对应的文件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"; 
} 

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

你忽略在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/, $_); 
+0

我对这段代码有一个简短的问题:perl如何知道当你第一次使用$ _(第2行)时,它是第一个文件的行,并且当你第二次使用$ _时(第6行),它是从第二个文件的行?或者说,在这些步骤之间改变$ _的输入的开关在哪里? – Prawn 2014-09-09 08:59:36

+0

在if(...)条件下'$ _'被'$ _ = '重新分配。 – AnFi 2014-09-09 12:32:41

在每个循环中,您从每个文件读取两次。一旦进入while状态条件,并且一次进入while状态。

替换您同时符合:

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

这将导致病情的同时,如果任一文件达到最终失败。 如果文件有可能具有不同的长度,可以在while循环之后检查哪个文件没有达到eof。

+0

非常感谢!它工作完美!但是有一个问题,你能告诉我IO :: Handle是干什么的吗?不知道我是否完全明白你在做什么 – Prawn 2014-09-04 15:03:21

+4

不需要'IO :: Handle'。你可以用'until(eof $ HMP或eof $ AL){...}'来达到同样的效果,这种情况下IMO更具可读性。 – Borodin 2014-09-04 15:05:29

+0

IO :: Handle用于处理输入/输出流。请参阅文档:http://perldoc.perl.org/IO/Handle.html – 2014-09-04 15:23:17

几个简单的诀窍:

只要你有非常类似的重复的代码行,这是有可能做的事情更经济的方式的标志。例如,下面的代码:

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工作,在开发脚本时编写调试语句和测试确实有帮助,这样您就可以确定知道发生了什么。在脚本执行时用自己的代码*地声明变量的值,这些语句在调试过程中确实有帮助。一旦代码投入使用,“say”语句可以被注释掉,或者您可以使用环境或程序变量来打开和关闭它们 - 例如,

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

如果你还没有发现Data::Dumper,它会成为你最好的朋友在开发过程中:它可以让你检查数据结构和对象的内容,并制定出为什么你精心编写的代码未正常工作这应该!

Perl测试对于覆盖SO答案来说是一个太大的问题,但在perl文档中看看TestTest::Simple。编写脚本时编写测试套件可以节省大量时间 - 而且比以后更容易!

+0

@i惊慌的外星人:哇非常感谢所有这些有用的提示!我非常感谢他们,因为我几天前才刚刚开始学习perl,所以任何帮助只是欢迎我!我会查找你提到的东西,我相信我会从中获益匪浅! =) – Prawn 2014-09-04 15:33:13

+0

@Prawn很高兴有帮助! :d – 2014-09-04 19:35:40