我有这样的代码:
#!/usr/bin/perl
use strict;
use warnings;
my %proteins = qw/
UUU F UUC F UUA L UUG L UCU S UCC S UCA S UCG S UAU Y UAC Y UGU C UGC C UGG W
CUU L CUC L CUA L CUG L CCU P CCC P CCA P CCG P CAU H CAC H CAA Q CAG Q CGU R CGC R CGA R CGG R
AUU I AUC I AUA I AUG M ACU T ACC T ACA T ACG T AAU N AAC N AAA K AAG K AGU S AGC S AGA R AGG R
GUU V GUC V GUA V GUG V GCU A GCC A GCA A GCG A GAU D GAC D GAA E GAG E GGU G GGC G GGA G GGG G
/;
open(INPUT,"<dna.txt");
while (<INPUT>) {
tr/[a,c,g,t]/[A,C,G,T]/;
y/GCTA/CGAU/;
foreach my $protein (/(...)/g) {
if (defined $proteins{$protein}) {
print $proteins{$protein};
}
}
}
close(INPUT);
此代码与我的其他问题的答案有关:DNA to RNA and Getting Proteins with Perl
该计划的输出是:
SIMQNISGREAT
如何使用Perl重写该代码,它将在命令行上运行,并且将用更少的代码(如果可能的话,一行代码)重写?
PS 1: dna.txt就是这样:
TCATAATACGTTTTGTATTCGCCAGCGCTTCGGTGT
PS 2:如果代码的行数较少,则可以接受将my %proteins
变量写入文件。
答案 0 :(得分:3)
我建议的唯一更改是简化while
循环:
while (<INPUT>) {
tr/acgt/ACGT/;
tr/GCTA/CGAU/;
foreach my $protein (/(...)/g) {
if (defined $proteins{$protein}) {
print $proteins{$protein};
}
}
}
由于y
和tr
是同义词,因此您应该只使用其中一个。我认为tr
读取的内容比y
更好,所以我选择了tr
。此外,你用非常不同的方式调用它们,但这应该是相同的效果,只提到你实际改变的字母。 (所有其他角色都被转换为自己。这使得很多更难以看到实际被改变的内容。)
您可能希望删除open(INPUT,"<dna.txt");
和相应的close(INPUT);
行,因为它们使得在shell管道中使用您的程序或使用不同的输入文件更加困难。但这取决于你,如果输入文件总是是dna.txt
而且从来没有任何不同,那就没关系。
答案 1 :(得分:2)
#!/usr/bin/perl
%p=qw/UUU F UUC F UUA L UUG L UCU S UCC S UCA S UCG S UAU Y UAC Y UGU C UGC C UGG W
CUU L CUC L CUA L CUG L CCU P CCC P CCA P CCG P CAU H CAC H CAA Q CAG Q CGU R CGC R CGA R CGG R
AUU I AUC I AUA I AUG M ACU T ACC T ACA T ACG T AAU N AAC N AAA K AAG K AGU S AGC S AGA R AGG R
GUU V GUC V GUA V GUG V GCU A GCC A GCA A GCG A GAU D GAC D GAA E GAG E GGU G GGC G GGA G GGG G/;
$_=uc<DATA>;y/GCTA/CGAU/;map{print if$_=$p{$_}}/(...)/g
__DATA__
TCATAATACGTTTTGTATTCGCCAGCGCTTCGGTGT
呼。我能想出最好的,至少这个很快。如果您确定输入始终为大写,则还可以删除uc
另外两个字符。或者,如果输入始终相同,您可以立即将其分配给$_
,而不是从任何地方读取。
我想我不需要说这段代码应该不在生产环境中使用,或者除了纯粹的乐趣以外的任何其他地方。在进行实际编程时,可读性几乎总是胜过紧凑性。
我在评论中提到的其他一些版本:
从文件中读取%p和DNA:
#!/usr/bin/perl
open A,"<p.txt";map{map{/(...)/;$p{$1}=chop}/(... .)/g}<A>;
open B,"<dna.txt";$_=uc<B>;y/GCTA/CGAU/;map{print if$_=$p{$_}}/(...)/g
来自perl -e
的shell:
perl -e 'open A,"<p.txt";map{map{/(...)/;$p{$1}=chop}/(... .)/g}<A>;open B,"<dna.txt";$_=uc<B>;y/GCTA/CGAU/;map{print if$_=$p{$_}}/(...)/g'
答案 2 :(得分:2)
某人(@kamaci)在另一个帖子中叫了我的名字。这是我在将蛋白质表保持在命令行时能够想到的最好的结果:
perl -nE'say+map+substr("FYVDINLHL%VEMKLQL%VEIKLQFYVDINLHCSGASTRPWSGARTRP%SGARTRPCSGASTR",(s/GGG/GGC/i,vec($_,0,32)&101058048)%63,1),/.../g' dna.txt
(Shell引用,Windows引用交换'
和"
个字符)。此版本标记了%
的无效密码子,您可以通过在适当的位置添加=~y/%//d
来解决此问题。
提示:这从RNA三元组的原始ASCII编码中选出6位,在0到101058048之间给出64个代码;为了得到一个字符串索引,我减少了模63的结果,但这创建了一个双映射,令人遗憾地必须编写两个不同的蛋白质。 s/GGG/GGC/i
将其中一个映射到编码正确蛋白质的另一个。
另请注意%
运算符之前的括号,两者将,
运算符与substr
和的参数列表隔离开来修复&
vs %
的优先顺序。如果您曾在生产代码中使用它,那么您就是一个坏人,坏人。
答案 3 :(得分:1)
大多数事情已经被指出,特别是可读性很重要。我不会尝试减少程序,而不是以下内容。
use strict;
use warnings;
# http://stackoverflow.com/questions/5402405/
my $fnprot = shift || 'proteins.txt';
my $fndna = shift || 'dna.txt';
# build protein table
open my $fhprot, '<', $fnprot or die "open $fnprot: $!";
my %proteins = split /\s+/, do { local $/; <$fhprot> };
close $fhprot;
# process dna data
my @result;
open my $fhdna, '<', $fndna or die "open $fndna: $!";
while (<$fhdna>) {
tr/acgt/ACGT/;
tr/GCTA/CGAU/;
push @result, map $proteins{$_}, grep defined $proteins{$_}, m/(...)/g;
}
close $fhdna;
# check correctness of result (given input as per original post)
my $expected = 'SIMQNISGREAT';
my $got = join '', @result;
die "@result is not expected" if $got ne $expected;
print "@result - $got\n";
我添加的唯一“单行”事物是while循环中的push map grep m//g
。请注意,Perl 5.10添加了“已定义或”运算符 - //
- 允许您编写:
push @result, map $proteins{$_} // (), m/(...)/g;
啊好吧,open do local $/
文件slurp成语很方便将小文件插入内存。希望你觉得它有点鼓舞人心。 : - )
答案 4 :(得分:0)
如果将蛋白质数据写入另一个文件,空格分隔且没有换行符。因此,您可以通过一次读取文件来导入数据。
#!/usr/bin/perl
use strict;
use warnings;
open(INPUT, "<mydata.txt");
open(DATA, "<proteins.txt");
my %proteins = split(" ",<DATA>);
while (<INPUT>) {
tr/GCTA/CGAU/;
while(/(\w{3})/gi) {print $proteins{$1} if (exists($proteins{$1}))};
}
close(INPUT);
close(DATA);
您可以删除代码行“ tr / a,c,g,t / A,C,G,T / ”因为匹配运算符有案例选项不敏感( i 选项)。原始的 foreach 循环可以像上面的代码一样进行优化。 $ 1 变量这里匹配模式结果在匹配操作的括号内 /(\ w {3})/ gi