簡體   English   中英

為什么我的Perl for loop會提前退出?

[英]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])類的數組可確保正確的線對始終在一起。

對於您要執行的操作,我不清楚的是:

  • a)您是否正在生成一個共有序列,其中兩個序列僅在缺口之間存在差異
  • b)您的2個序列是否有顯着差異,並且您試圖排除不匹配的部分,然后產生共識?

那么,第一對代表您的數據,還是更像第二對?

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM