[英]Why does my Perl for loop exit early?
我試圖讓一個Perl循環從包含6個元素的數組開始工作。 我希望循環從數組中拉出兩個元素,執行某些功能,然后回退並從數組中拉出接下來的兩個元素,直到數組用完元素為止。 問題是循環僅拉出前兩個元素,然后停止。 這里有些幫助將不勝感激。
my open(infile, 'dnadata.txt');
my @data = < infile>;
chomp @data;
#print @data; #Debug
my $aminoacids = 'ARNDCQEGHILKMFPSTWYV';
my $aalen = length($aminoacids);
my $i=0;
my $j=0;
my @matrix =();
for(my $i=0; $i<2; $i++){
for( my $j=0; $j<$aalen; $j++){
$matrix[$i][$j] = 0;
}
}
該程序的准則指出,該程序應忽略程序中存在的差距。 這意味着與缺口匹配的DNA代碼應被忽略。 因此,推入的代碼需要消除與空白鏈接的對齊方式。
我需要將數組的長度修改為2,因為我要在循環的這一部分比較兩個序列。
#$lemseqcomp = $lenarray / 2;
#print $lenseqcomp;
#I need to initialize these saclar values.
$junk1 = " ";
$junk2 = " ";
$seq1 = " ";
$seq2 = " ";
這是導致問題的循環。 我相信,第一個循環應移回數組,並在每次循環時退出下一個元素,但事實並非如此。
for($i=0; $i<$lenarray; $i++){
#This code should remove the the last value of the array once and
#then a second time. The sequences should be the same length at this point.
my $last1 =pop(@data1);
my $last2 =pop(@data1);
for($i=0; $i<length($last1); $i++){
my $letter1 = substr($last1, $i, 1);
my $letter2 = substr($last2, $i, 1);
if(($letter1 eq '-')|| ($letter2 eq '-')){
#I need to put the sequences I am getting rid of somewhere. Here is a good place as any.
$junk1 = $letter1 . $junk1;
$junk2 = $letter1 . $junk2;
}
else{
$seq1 = $letter1 . $seq1;
$seq2 = $letter2 . $seq2;
}
}
}
print "$seq1\n";
print "$seq2\n";
print "@data1\n";
我實際上正在嘗試從頭開始創建替換矩陣並返回數據。 代碼看起來很奇怪的原因是因為它實際上還沒有完成,所以我被卡住了。 如果有人好奇,這就是測試順序。
YFRFR
YF-FR
FRFRFR
ARFRFR
YFYFR-F
YFRFRYF
首先,如果要使用序列數據,請使用BioPerl 。 生活會容易得多。 然而...
由於您知道將成對比較輸入文件中的行,因此將它們讀入反映該行的數據結構是有意義的。 正如其他地方所建議的那樣,@ @data[[line1, line2],[line3,line4])
類的數組可確保正確的線對始終在一起。
對於您要執行的操作,我不清楚的是:
那么,第一對代表您的數據,還是更像第二對?
ATCG---AAActctgGGGGG--taGC
ATCGcccAAActctgGGGGGTTtaGC
ATCG---AAActctgGGGGG--taGCTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
ATCGcccAAActctgGGGGGTTtaGCGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
問題是您在兩個循環中都使用$i
作為計數器變量,因此內部循環從外部循環中修改計數器。 嘗試將內部循環的計數器更改為$j
,或使用my
正確定位它們。
不要將值存儲為數組,而應存儲為二維數組:
my @dataset = ([$val1, $val2], [$val3, $val4]);
要么
my @dataset;
push (@dataset, [$val_n1, $val_n2]);
然后:
for my $value (@dataset) {
### Do stuff with $value->[0] and $value->[1]
}
您的代碼中有很多奇怪的事情:正在初始化矩陣,然后不使用它; 將整個文件讀入數組; 掃描字符串C樣式,但隨后對不匹配的值不執行任何操作; 最后,僅打印最后兩個處理后的值(在您的情況下,這是數組的前兩個元素,因為您正在使用pop。)
這是一個猜測。
use strict;
my $aminoacids = 'ARNDCQEGHILKMFPSTWYV';
# Preparing a regular expression. This is kind of useful if processing large
# amounts of data. This will match anything that is not in the string above.
my $regex = qr([^$aminoacids]);
# Our work function.
sub do_something {
my ($a, $b) = @_;
$a =~ s/$regex//g; # removing unwanted characters
$b =~ s/$regex//g; # ditto
# Printing, saving, whatever...
print "Something: $a - $b\n";
return ($a, $b);
}
my $prev;
while (<>) {
chomp;
if ($prev) {
do_something($prev, $_);
$prev = undef;
} else {
$prev = $_;
}
}
print STDERR "Warning: trailing data: $prev\n"
if $prev;
由於您是Perl /編程新手,因此我將展示您的第一個代碼塊的重寫,然后為您提供一些常規建議和鏈接。
讓我們看一下示例代碼的第一塊。 有很多東西串在一起,很難遵循。 我個人很笨,一次不能記住很多事情,所以我將問題分解為一些我可以理解的小片段。 這被稱為“塊”。
編寫程序塊的一種簡單方法是使用write子例程。 采取任何可能重復的特殊動作或想法,或者使當前代碼段變得冗長且難以理解,然后將其包裝成一個很好的整潔的程序包,並使其擺脫干擾。
如果您在代碼中增加空間以使其更易於閱讀,它也有幫助。 您的頭腦已經在努力尋找代碼湯,為什么要使事情變得比必要的更難? 將名稱進行分組,在名稱中使用_
,空行和縮進都可以。 還有一些約定可以幫助您,例如將所有大寫字母都設為常量值(不能或不應更改的值)。
use strict; # Using strict will help catch errors.
use warnings; # ditto for warnings.
use diagnostics; # diagnostics will help you understand the error messages
# Put constants at the top of your program.
# It makes them easy to find, and change as needed.
my $AMINO_ACIDS = 'ARNDCQEGHILKMFPSTWYV';
my $AMINO_COUNT = length($AMINO_ACIDS);
my $DATA_FILE = 'dnadata.txt';
# Here I am using subroutines to encapsulate complexity:
my @data = read_data_file( $DATA_FILE );
my @matrix = initialize_matrix( 2, $amino_count, 0 );
# now we are done with the first block of code and can do more stuff
...
# This section down here looks kind of big, but it is mostly comments.
# Remove the didactic comments and suddenly the code is much more compact.
# Here are the actual subs that I abstracted out above.
# It helps to document your subs:
# - what they do
# - what arguments they take
# - what they return
# Read a data file and returns an array of dna strings read from the file.
#
# Arguments
# data_file => path to the data file to read
sub read_data_file {
my $data_file = shift;
# Here I am using a 3 argument open, and a lexical filehandle.
open( my $infile, '<', $data_file )
or die "Unable to open dnadata.txt - $!\n";
# I've left slurping the whole file intact, even though it can be very inefficient.
# Other times it is just what the doctor ordered.
my @data = <$infile>;
chomp @data;
# I return the data array rather than a reference
# to keep things simple since you are just learning.
#
# In my code, I'd pass a reference.
return @data;
}
# Initialize a matrix (or 2-d array) with a specified value.
#
# Arguments
# $i => width of matrix
# $j => height of matrix
# $value => initial value
sub initialize_matrix {
my $i = shift;
my $j = shift;
my $value = shift;
# I use two powerful perlisms here: map and the range operator.
#
# map is a list contsruction function that is very very powerful.
# it calls the code in brackets for each member of the the list it operates against.
# Think of it as a for loop that keeps the result of each iteration,
# and then builds an array out of the results.
#
# The range operator `..` creates a list of intervening values. For example:
# (1..5) is the same as (1, 2, 3, 4, 5)
my @matrix = map {
[ ($value) x $i ]
} 1..$j;
# So here we make a list of numbers from 1 to $j.
# For each member of the list we
# create an anonymous array containing a list of $i copies of $value.
# Then we add the anonymous array to the matrix.
return @matrix;
}
現在代碼重寫已經完成,這里是一些鏈接:
這是我寫的標題為“如何編寫程序”的回復 。 它提供了一些有關如何按照規范編寫軟件項目的基本指南。 它是針對初學者的。 我希望你覺得這對你有幫助。 如果沒有其他要求,其中的鏈接應該很方便。
對於從Perl開始的初學者,沒有什么比學習Perl更好的書了。
我還建議前往Perlmonks尋求Perl的幫助和指導。 這是一個活躍的Perl特定社區站點,非常聰明,友好的人很樂意為您提供幫助。 有點像堆棧溢出,但是更加集中。
祝好運!
您可以使用while循環內的splice一次從數組中讀取兩個元素,而不必使用C樣式的for循環:
while (my ($letter1, $letter2) = splice(@data, 0, 2))
{
# stuff...
}
我在下面清理了您的其他一些代碼:
use strict;
use warnings;
open(my $infile, '<', 'dnadata.txt');
my @data = <$infile>;
close $infile;
chomp @data;
my $aminoacids = 'ARNDCQEGHILKMFPSTWYV';
my $aalen = length($aminoacids);
# initialize a 2 x 21 array for holding the amino acid data
my $matrix;
foreach my $i (0 .. 1)
{
foreach my $j (0 .. $aalen-1)
{
$matrix->[$i][$j] = 0;
}
}
# Process all letters in the DNA data
while (my ($letter1, $letter2) = splice(@data, 0, 2))
{
# do something... not sure what?
# you appear to want to look up the letters in a reference table, perhaps $aminoacids?
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.