它是一种生物信息学概念,但程序化问题。我已经尝试了很多,最后我来到这里。我读起来就好了。
ATGGAAG
TGGAAGT
GGAAGTC
GAAGTCG
AAGTCGC
AGTCGCG
GTCGCGG
TCGCGGA
CGCGGAA
GCGGAAT
CGGAATC
现在我想做的是,以一种简单的方式,
取第一次读取的最后6个残基 - >检查是否有任何其他读数以这6个残基开始,如果是,则将该读数的最后一个残基添加到第一个读数 - >再次与第二次阅读相同,等等。
以下是我到目前为止所尝试的代码。
#!/usr/bin/perl -w
use strict;
use warnings;
my $in = $ARGV[0];
open(IN, $in);
my @short_reads = <IN>;
my $first_read = $short_reads[0];
chomp $first_read;
my @all_end_res;
for(my $i=0; $i<=$#short_reads; $i++){
chomp $short_reads[$i];
my $end_of_kmers = substr($short_reads[$i], -6);
if($short_reads[$i+1] =~ /^$end_of_kmers/){
my $end_res = substr($short_reads[$i], -1);
push(@all_end_res, $end_res);
}
}
my $end_res2 = join('', @all_end_res);
print $first_read.$end_res2,"\n\n";
最后我应该得到ATGGAAGTCGCGGAATC
之类的输出,但我得到的是ATGGAAGGTCGCGGAAT
。错误必须在if
,任何帮助都非常感谢。
答案 0 :(得分:2)
IT有三个大问题。
你刚刚打到第二个。问题在于您考虑这项任务的方式。你想的是我有这个字符串,如果下一个一个重叠,我会将这一个字符添加到结果中。但在这种情况下正确思考我有这一个字符串,如果它与上一个字符串或我到目前为止所阅读的内容重叠,我将添加一个或下一个字符。
#!/usr/bin/env perl
use strict;
use warnings;
use constant LENGTH => 6;
my $read = <>;
chomp $read;
while (<>) {
chomp;
last unless length > LENGTH;
if ( substr( $read, -LENGTH() ) eq substr( $_, 0, LENGTH ) ) {
$read .= substr( $_, LENGTH );
}
else {last}
}
print $read, "\n";
我没有得到这个ARGV[0]
的东西。它毫无用武且不灵活。
$ chmod +x code.pl
$ cat data
ATGGAAG
TGGAAGT
GGAAGTC
GAAGTCG
AAGTCGC
AGTCGCG
GTCGCGG
TCGCGGA
CGCGGAA
GCGGAAT
CGGAATC
$ ./code.pl data
ATGGAAGTCGCGGAATC
但是你没有定义如果数据不重叠会发生什么。应该有一些恢复或错误?你也可以更严格
last unless length == LENGTH + 1;
修改强>:
如果您喜欢使用数组,请尝试避免使用for(;;)
。它容易出错。 (BTW for (my $i = 0; $i < @a; $i++)
更具惯用性。)
my @short_reads = <>;
chomp @short_reads;
my @all_end_res;
for my $i (1 .. $#short_reads) {
my $prev_read = $short_reads[$i-1];
my $curr_read = $short_reads[$i+1];
my $end_of_kmers = substr($prev_read, -6);
if ( $curr_read =~ /^\Q$end_of_kmers(.)/ ) {
push @all_end_res, $1;
}
}
print $short_reads[0], join('', @all_end_res), "\n";
性能和内存差异可忽略不计,最多可达数千行。现在您可以问为什么要将字符累积到数组中而不是将其累积到字符串中。
my @short_reads = <>;
chomp @short_reads;
my $read = $short_reads[0];
for my $i (1 .. $#short_reads) {
my $prev_read = $short_reads[$i-1];
my $curr_read = $short_reads[$i+1];
my $end_of_kmers = substr($prev_read, -6);
if ( $curr_read =~ /^\Q$end_of_kmers(.)/ ) {
$read .= $1;
}
}
print "$read\n";
现在问题是为什么在$prev_read
内有$end_of_kmers
时使用$read
。
my @short_reads = <>;
chomp @short_reads;
my $read = $short_reads[0];
for my $i (1 .. $#short_reads) {
my $curr_read = $short_reads[$i+1];
my $end_of_kmers = substr($read, -6);
if ( $curr_read =~ /^\Q$end_of_kmers(.)/ ) {
$read .= $1;
}
}
print "$read\n";
现在你可以问我为什么需要索引了。你应该删除第一行来处理数组的其余部分。
my @short_reads = <>;
chomp @short_reads;
my $read = shift @short_reads;
for my $curr_read (@short_reads) {
my $end_of_kmers = substr($read, -6);
if ( $curr_read =~ /^\Q$end_of_kmers(.)/ ) {
$read .= $1;
}
}
print "$read\n";
通过更多的步骤和调整,您将最终得到我最初发布的代码。我根本不需要数组,因为我只查看当前行和累加器。不同之处在于您如何看待问题。如果您考虑数组和索引以及循环或数据流,数据处理和状态/累加器。凭借更多的经验,您无需执行所有这些步骤,只需采用不同的解决问题的方法来制定最终解决方案。
<强> EDIT2 强>:
使用substr
和eq
然后使用正则表达式几乎快十倍。
$ time ./code.pl data.out > data.test
real 0m0.480s
user 0m0.468s
sys 0m0.008s
$ time ./code2.pl data.out > data2.test
real 0m4.520s
user 0m4.516s
sys 0m0.000s
$ cmp data.test data2.test && echo OK
OK
$ wc -c data.out data.test
6717368 data.out
839678 data.test
答案 1 :(得分:0)
稍加修改:
use warnings;
use strict;
open my $in, '<', $ARGV[0] or die $!;
chomp(my @short_reads = <$in>);
my $first_read = $short_reads[0];
my @all_end_res;
for(my $i=0; $i<=$#short_reads; $i++){
chomp $short_reads[$i];
my $end_of_kmers = substr($short_reads[$i], -6);
my ($next_read) = $short_reads[$i+1];
if( (defined $next_read) and ($next_read =~ /^\Q$end_of_kmers/)){
my $end_res = substr($next_read, -1);
push(@all_end_res, $end_res);
}
}
my $end_res2 = join('', @all_end_res);
print $first_read.$end_res2,"\n";
ATGGAAGTCGCGGAATC