所以我尝试编写一个脚本,将一个文件的每一行与其对应的文件行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循环之外启动数组,但没有任何作用。任何人都可以告诉我脚本中哪里出错了? (顺便说一下,我知道风格并不漂亮,所以如果你们有任何关于如何使这个脚本更紧凑的建议,请随意这样做!毕竟我想学习。)
答案 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文档中的Test和Test::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/, $_);