0

次のスクリプトを使用して、ファイル内のシーケンス (行) の順序をシャッフルしようとしています。値を「初期化」する方法がわかりません -- 助けてください!

print "Please enter filename (without extension): ";
my $input = <>;
chomp $input;

use strict;
use warnings;

print "Please enter total no. of sequence in fasta file: ";
my $orig_size = <>*2-1;
chomp $orig_size;

open INFILE, "$input.fasta"
   or die "Error opening input file for shuffling!";
open SHUFFLED, ">"."$input"."_shuffled.fasta"
   or die "Error creating shuffled output file!";

my @array  = (0); # Need to initialise 1st element in array1&2 for the shift function
my @array2 = (0);
my $i      = 1;
my $index  = 0;
my $index2 = 0;

while (my @line = <INFILE>){

    while ($i <= $orig_size) { 

        $array[$i] = $line[$index];
        $array[$i] =~ s/(.)\s/$1/seg;

        $index++;
        $array2[$i] = $line[$index];
        $array2[$i] =~ s/(.)\s/$1/seg;

        $i++;
        $index++;
    }
}

my $array  = shift (@array); 
my $array2 = shift (@array2);

for ($i = my $header_size; $i >= 0; $i--) { 

    my $j = int rand ($i+1);
    next if $i == $j;
    @array[$i,$j]  = @array[$j,$i];
    @array2[$i,$j] = @array2[$j,$i];
}

while ($index2 <= my $header_size) { 

    print SHUFFLED "$array[$index2]\n";
    print SHUFFLED "$array2[$index2]\n";
    $index2++;
}
close INFILE;
close SHUFFLED;

次の警告が表示されます。

Use of uninitialized value in substitution (s///) at fasta_corrector6.pl line 27, <INFILE> line 578914.
Use of uninitialized value in substitution (s///) at fasta_corrector6.pl line 31, <INFILE> line 578914.
Use of uninitialized value in numeric ge (>=) at fasta_corrector6.pl line 40, <INFILE> line 578914.
Use of uninitialized value in addition (+) at fasta_corrector6.pl line 41, <INFILE> line 578914.
Use of uninitialized value in numeric eq (==) at fasta_corrector6.pl line 42, <INFILE> line 578914.
Use of uninitialized value in numeric le (<=) at fasta_corrector6.pl line 47, <INFILE> line 578914.
Use of uninitialized value in numeric le (<=) at fasta_corrector6.pl line 50, <INFILE> line 578914.

4

3 に答える 3

3

まず、入力ファイル全体を次のように読み込みます。

  use IO::File;
  my @lines = IO::File->new($file_name)->getlines;

次にシャッフルします。

  use List::Util 'shuffle';
  my @shuffled_lines = shuffle(@lines);

次に、それらを書き出します。

  IO::File->new($new_file_name, "w")->print(@shuffled_lines);

Perl FAQに、配列をシャッフルする方法に関するエントリがあります。別のエントリでは、ファイルを一度に読み取るさまざまな方法について説明しています。Perl の FAQ には、多くの一般的なことを行う方法に関する多くのサンプルとトリビアが含まれています。これは、Perl についてさらに学習を続けるのに適した場所です。

于 2012-09-13T16:44:34.350 に答える
2

正確に何が問題なのかを特定することはできませんが、コードにはいくつかの奇妙な点があります。

ダイヤモンドオペレーター

Perl の Diamond 演算子<FILEHANDLE>は、ファイルハンドルから行を読み取ります。ファイルハンドルが指定されていない場合、各コマンドライン引数 ( @ARGV) はファイルとして扱われ、読み取られます。引数がない場合は、STDINが使用されます。これを自分で指定することをお勧めします。また、後でではなく、行で算術を行うchomp 前に行う必要があります。数字で始まらない文字列は数値として扱われることに注意してください0。(正規表現を使用して) 数値であることを確認し、エラー処理を含める必要があります。

Diamond/Readline オペレーターは状況依存型です。スカラー コンテキスト (条件、スカラー代入など) で指定された場合、1 行が返されます。関数のパラメータや配列の代入など、リスト コンテキストで指定すると、すべての行が配列として返されます。そう

while (my @line = <INFILE>) { ...

1行ではなくすべての行が表示されるため、次と同等です

my @line;
if (@line = <INFILE>) { ...

アレイ体操

行を読み込んだ後、手動でチョッピングを試みます。ここでは、 , のすべての末尾の空白を@line1 行で削除します。

s/\s+$// foreach @line;

そしてここで、先頭以外の空白をすべて削除します (正規表現が実際に行っていること):

s/(?<!^)\s//g foreach @line;

要素を 2 つの配列に交互に詰め込むには、次のようにすることもできます。

for my $i (0 .. $#@line) {
   if ($i % 2) {
     push @array1, shift @line;
   } else {
     push @array2, shift @line;
   }
}

また

my $i = 0;
while (@line) {
   push ($i++ % 2 ? @array1 : @array2), shift @line
}

配列インデックスを手動で管理するのは面倒で、エラーが発生しやすくなります。

あなたのforループは、慣用的に次のように書くことができます

for my $i (reverse 0 .. $header_size)

$header_size以前に宣言されていない場合、ループの初期化内で宣言することは可能ですが、undef値が生成されることに注意してください。したがってundef$i算術undef演算では使用しないでください。割り当ては常に右側を左側に割り当てます。

于 2012-09-13T16:36:06.297 に答える
2

あなたの前の質問で、私はこの回答$header_sizeを提供しました。ループ条件で使用されるという名前の変数を初期化していないため、コードが失敗したことに注意してください。その間違いを繰り返しただけでなく、変数myにアクセスしようとするたびに変数の宣言を開始することで、それを詳しく説明しました。

for ($i = my $header_size; $i >= 0; $i--) { 
#         ^^--- wrong!

while ($index2 <= my $header_size) { 
#                 ^^--- wrong!

で宣言された変数は、デフォルトでmyは空 ( undef) です。$index2はtrue と評価されるundefため (ただし、初期化されていない警告が表示されます)、ループは 1 回だけ実行されます。0 <= undef

私のアドバイスに従って、 の値を設定してください$header_sizemyまた、変数を使用するたびにではなく、変数を宣言するときに のみ使用してください。

より良い解決策

上記のエラーを見ると、入力ファイルがかなり大きいようです。ファイルに 500,000 行を超える行がある場合は、スクリプトを実行するために大量のメモリが消費されることを意味します。Tie::Fileなどのモジュールを使用して、配列インデックスのみを操作することは価値がある場合があります。例えば:

use strict;
use warnings;
use Tie::File;
use List::Util qw(shuffle);

tie my @file, 'Tie::File', $filename or die $!;
for my $lineno (shuffle 0 .. $#file) {
    print $line[$lineno];
}
untie @file; # all done
于 2012-09-13T19:06:02.890 に答える