Como reescrever o código de uma linha (ou menos código de linha na linha de comando) deste código em Perl?

StackOverflow https://stackoverflow.com/questions/5402405

  •  28-10-2019
  •  | 
  •  

Pergunta

Eu tenho um código assim:

#!/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);

Este código está relacionado à resposta da minha outra pergunta: DNA para RNAe obtendo proteínas com Perl

O resultado do programa é:

SIMQNISGREAT

Como posso reescrever esse código com Perl, ele será executado na linha de comando e será reescrito com menos código (se possível, um código de linha)?

PS 1: dna.txt é assim:

TCATAATACGTTTTGTATTCGCCAGCGCTTCGGTGT

PS 2: Se o código tiver menos linhas, é aceito escrever a variável my %proteins em um arquivo.

Foi útil?

Solução

Alguém (@kamaci) chamou meu nome em outro tópico. Isso é o melhor que posso fazer enquanto mantenho a tabela de proteínas na linha de comando:

perl -nE'say+map+substr("FYVDINLHL%VEMKLQL%VEIKLQFYVDINLHCSGASTRPWSGARTRP%SGARTRPCSGASTR",(s/GGG/GGC/i,vec($_,0,32)&101058048)%63,1),/.../g' dna.txt

(citação de shell, para Windows cita ' de troca e caracteres "). Esta versão marca códons inválidos com %, você provavelmente pode corrigir isso adicionando =~y/%//d em um local apropriado.

Dica: Isso seleciona 6 bits da codificação ASCII bruta de um triplo de RNA, fornecendo 64 códigos entre 0 e 101058048; para obter um índice de string, reduzo o módulo de resultado 63, mas isso cria um mapeamento duplo que, infelizmente, teve que codificar duas proteínas diferentes. O s/GGG/GGC/i mapeia um deles para outro que codifica a proteína certa.

Observe também os parênteses antes do operador %, que ambos isolam o operador , da lista de argumentos de substr e corrigem a precedência de & vs %. Se você já usou isso no código de produção, você é uma pessoa má.

Outras dicas

As únicas alterações que eu recomendaria fazer são simplificar seu loop while:

while (<INPUT>) {
    tr/acgt/ACGT/;
    tr/GCTA/CGAU/;
    foreach my $protein (/(...)/g) {
        if (defined $proteins{$protein}) {
            print $proteins{$protein};
        }
    }
}

Como y e tr são sinônimos, você deve usar apenas um deles.Acho que tr lê melhor do que y, então escolhi tr.Além disso, você as estava chamando de maneira muito diferente, mas este deve ser o mesmo efeito e apenas menciona as letras que você realmente mudou.(Todos os outros personagens estavam sendo transpostos para si mesmos. Isso torna muito mais difícil ver o que realmente está sendo alterado.)

Você pode querer remover o open(INPUT,"<dna.txt"); e as linhas close(INPUT); correspondentes, pois eles tornam muito mais difícil usar seu programa em pipelines de shell ou com diferentes arquivos de entrada.Mas isso é com você, se o arquivo de entrada será sempre dna.txt e nunca algo diferente, está tudo bem.

#!/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

Ufa.É o melhor que consigo pensar, pelo menos assim rapidamente.Se você tiver certeza de que a entrada já está sempre em maiúsculas, você também pode descartar o uc salvando outros dois caracteres.Ou se a entrada for sempre a mesma, você pode atribuí-la a $_ imediatamente, em vez de lê-la de qualquer lugar.

Acho que não preciso dizer que este código não deve ser usado em ambientes de produção ou em qualquer outro lugar que não seja pura diversão.Ao fazer a programação real, a legibilidade quase sempre vence a compactação.

Algumas outras versões que mencionei nos comentários:

Lendo% pe o DNA dos arquivos:

#!/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

Do shell com perl -e:

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'

Muitas coisas já foram apontadas, especialmente a legibilidade é importante.Eu não tentaria reduzir o programa mais do que o seguinte.

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";

A única coisa de "uma linha" que adicionei é o push map grep m//g no loop while.Observe que o Perl 5.10 adiciona o operador "definido ou" - // - que permite que você escreva:

push @result, map $proteins{$_} // (), m/(...)/g;

Certo, o idioma slurp do arquivo open do local $/ é útil para inserir pequenos arquivos na memória.Espero que você ache isso um pouco inspirador.:-)

Se gravar dados de proteínas em outro arquivo, delimitado por espaço e sem quebra de linha.Portanto, você pode importar dados lendo o arquivo uma vez.

#!/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);

Você pode remover a linha de código " tr / a, c, g, t / A, C, G, T / " porque o operador de correspondência tem opção para maiúsculas e minúsculasinsensível (opção i ).E o loop foreach original pode ser otimizado como o código acima.A variável $1 aqui é o resultado do padrão combinado entre parênteses da operação de combinação /(\w{3})/gi

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top