我正在尝试使用以下脚本来重排文件中序列(行)的顺序。我不确定如何“初始化”值 - 请帮助!
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.
答案 0 :(得分: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);
有关how to shuffle an array的Perl常见问题解答中有一个条目。另一个条目tells of the many ways to read a file in one go。 Perl常见问题包含大量关于如何做许多常见事情的样本和琐事 - 这是继续学习更多关于Perl的好地方。
答案 1 :(得分:2)
我无法确定究竟出了什么问题,但您的代码有些奇怪:
Perl的Diamond运算符<FILEHANDLE>
从文件句柄中读取一行。如果未提供文件句柄,则将每个命令行Argument(@ARGV
)视为文件并读取。如果没有参数,则使用STDIN
。更好地自己指定。你还应该chomp
在之前使用该行进行arithemtics,而不是之后。请注意,不以数字开头的字符串将被视为数字0
。你应该检查数字(使用正则表达式?)并包括错误处理。
Diamond / Readline运算符对上下文敏感。如果在标量上下文中给出(例如,条件,标量赋值),则返回一行。如果在列表上下文中给出,例如作为函数参数或数组赋值,它将所有行作为数组返回。所以
while (my @line = <INFILE>) { ...
不会给你一行但是所有行都相当于
my @line;
if (@line = <INFILE>) { ...
在阅读完行后,您尝试进行一些手动咀嚼。在这里,我在@line
中删除所有尾随的空格,在一行中:
s/\s+$// foreach @line;
在这里,我删除了所有非领先的空格(你的正则表达式实际上是在做什么):
s/(?<!^)\s//g foreach @line;
要将一个元素交替填充到两个数组中,这可能也有效:
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-loop可以写成mor idiomatic
for my $i (reverse 0 .. $header_size)
请注意,如果之前没有声明,则可以在循环初始化中声明$header_size
,但它会产生undef
值,因此您将undef
分配给$i
导致一些错误消息,因为undef
不应该用于arithemtic操作。作业总是将右侧分配给左侧。
答案 2 :(得分:2)
关于您之前的问题,我提供了this answer,并注意到您的代码失败了,因为您尚未初始化循环条件中使用的名为$header_size
的变量。你不仅重复了这个错误,你已经通过每次尝试访问它时开始用my
声明变量来详细阐述它。
for ($i = my $header_size; $i >= 0; $i--) {
# ^^--- wrong!
while ($index2 <= my $header_size) {
# ^^--- wrong!
默认情况下,使用my
声明的变量为空(undef
)。 $index2
此处除了undef
之外永远不会包含任何内容,并且您的循环只会运行一次,因为0 <= undef
将评估为true(尽管有未初始化的警告)。
请接受我的建议并为$header_size
设置一个值。并且在声明变量时仅使用my
,而不是每次使用它时都使用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
。
更好的解决方案
看到上面的错误,您的输入文件似乎相当大。如果文件中有超过500,000行,则表示您的脚本将消耗大量内存来运行。使用Tie::File之类的模块并仅使用数组索引可能是值得的。例如:
{{1}}