Tradução de RNA para proteína

18

O RNA , como o DNA, é uma molécula encontrada nas células que codificam informações genéticas. É constituído por nucleotídeos , que são representados pelas bases adenina (A), citosina (C), guanina (G) e uracil (U). * Um códon é uma sequência de três nucleotídeos.

As proteínas são moléculas grandes que desempenham uma vasta gama de funções, como a queratina, encontrada nos cabelos e unhas, e a hemoglobina, que transporta oxigênio nas células sanguíneas. Eles são compostos de aminoácidos , que são codificados como códons nas moléculas de RNA. Às vezes, códons diferentes podem codificar para o mesmo aminoácido. Cada aminoácido é comumente representado por uma única letra, por exemplo H significa histidina.

Dada uma sequência de ACGU, você pode traduzi-la na sequência de proteínas correspondente?

* O DNA consiste em ACGT, onde o T é timina. Durante a transcrição do DNA para o RNA, a timina é substituída pelo uracil.


Entrada

A entrada será uma única sequência que consiste apenas nos caracteres ACGUem maiúsculas. Você pode escrever uma função ou um programa completo para esse desafio.

Resultado

Você pode optar por imprimir ou imprimir uma string (a última opção está disponível apenas no caso de uma função).

A tradução deve começar no códon inicial ( AUG, representado como M) e terminar no códon final (um de UAA, UAGou UGArepresentado como *). Há quatro casos em que a entrada pode ser inválida:

  • A entrada não começa com um codão de início
  • A entrada não termina com um códon de parada
  • O comprimento da entrada não é múltiplo de 3
  • A entrada contém um códon de parada em outro lugar que não no final

Em todos esses casos, Errordeve ser gerado. Observe que, diferentemente dos códons de parada, os códons de início podem aparecer após o início da string.

Caso contrário, você deve converter cada códon em seu respectivo aminoácido através da seguinte tabela de códons de RNA :

* UAA UAG UGA
A GCU GCC GCA GCG
C UGU UGC
D GAU GAC
E GAA GAG
F UUU UUC
G GGU GGC GGA GGG
H CAU CAC
I AUU AUC AUA
K AAA AAG
L UUA UUG CUU CUC CUA CUG
M AUG
N AAU AAC
P CCU CCC CCA CCG
Q CAA CAG
R CGU CGC CGA CGG AGA AGG
S UCU UCC UCA UCG AGU AGC
T ACU ACC ACA ACG
V GUU GUC GUA GUG
W UGG
Y UAU UAC

... e produz a string traduzida.

Exemplos

Casos inválidos:

<empty string> -> Error
AUG -> Error
UAA -> Error
AUGCUAG -> Error
AAAAAAA -> Error
GGGCACUAG -> Error
AUGAACGGA -> Error
AUGUAGUGA -> Error
AUGUUUGUUCCGUCGAAAUACCUAUGAACACGCUAA -> Error

Casos válidos:

AUGUGA -> M*
AUGAGGUGUAGCUGA -> MRCS*
AUGGGUGAGAAUGAAACGAUUUGCAGUUAA -> MGENETICS*
AUGCCAGUCGCACGAUUAGUUCACACGCUCUUGUAA -> MPVARLVHTLL*
AUGCUGCGGUCCUCGCAUCUAGCGUUGUGGUUAGGGUGUGUAACUUCGAGAACAGUGAGUCCCGUACCAGGUAGCAUAAUGCGAGCAAUGUCGUACGAUUCAUAG -> MLRSSHLALWLGCVTSRTVSPVPGSIMRAMSYDS*
AUGAAAAACAAGAAUACAACCACGACUAGAAGCAGGAGUAUAAUCAUGAUUCAACACCAGCAUCCACCCCCGCCUCGACGCCGGCGUCUACUCCUGCUUGAAGACGAGGAUGCAGCCGCGGCUGGAGGCGGGGGUGUAGUCGUGGUUUACUAUUCAUCCUCGUCUUGCUGGUGUUUAUUCUUGUUUUAA -> MKNKNTTTTRSRSIIMIQHQHPPPPRRRRLLLLEDEDAAAAGGGGVVVVYYSSSSCWCLFLF*

Edit: Adicionado mais casos de teste

Pontuação

Esse é o código golf, portanto o código com o menor número de bytes vence.

Nota: Eu não sou especialista em biologia molecular, portanto, sinta-se à vontade para me corrigir se eu tiver afirmado algo errado :)

Sp3000
fonte
11
Um tradutor adequado deve ser capaz de encontrar o quadro de leitura aberto em qualquer string, não apenas nos que começam com AUG!
Canadense1 de
@canadianer Ahaha sim eu considerei inicialmente isso, mas eu não queria fazer a pergunta muito complicada, trazendo em quadros de leitura aberta (ou mesmo traduzir múltiplas proteínas a partir de uma única corda) :)
SP3000
A cadeia vazia seria um caso de teste útil, porque interromperá algumas abordagens de teste com as quais a sequência decodificada começa Me termina *.
Peter Taylor
@PeterTaylor Adicionado, juntamente com alguns casos de teste mais curto :)
SP3000
11
Se você quisesse ser uma dor real, poderia usar DNA em vez de RNA, para ter quadros de leitura inversos também.
user137

Respostas:

6

CJam ( 97 93 92 91 bytes)

q"GACU"f#3/{4b"GGEDAAVVRSKNTTMIRRQHPPLLWC*YSSLF"{_s"MW""I*"er}%=}%s_'*/(1<"M"=*Qa=\"Error"?

Esta é uma porta da minha solução GolfScript com uma função de hash levemente aprimorada, porque, para minha surpresa, uma coisa que CJam não pediu emprestado ao GolfScript é tratar as strings como matrizes de números inteiros.

6 bytes salvos graças a sugestões do Optimizer (incluindo dois bytes de algo que eu pensei ter tentado e não funcionou - hein).

Peter Taylor
fonte
11
q"GACU"f#3/{4b"GGEDAAVVRSKNTTMIRRQHPPLLWC*YSSLF"{_s"MW""I*"er}%=}%s_'*/(1<"M"=*Q="Error"@?# 90
Optimizer
@ Otimizador, parte disso parece ser uma melhoria. No entanto, ele dá um erro de execução, ea comparação com Qem vez de [Q]é apenas incorreta.
Peter Taylor
1. você não copiou o código corretamente; quando o código abrange várias linhas nos comentários, ele recebe um caractere unicode estranho na quebra de linha. Você precisará digitar manualmente o código sozinho. 2. Veja a lógica, ela foi alterada para funcionar corretamente, portanto, [Q]a Qalteração está correta.
Optimizer
@Optimizer, tente o caso de testeAUGUAGUGA
Peter Taylor
11
Ah ok. Ainda [Q]->Qa
Otimizador
10

Caracteres JavaScript (ES6) 167 177 codificados em UTF8 como 167 177 bytes

... então espero que todos estejam felizes.

Editar De fato, não há necessidade de um caso especial para o último bloco muito curto. Se os últimos 2 (ou 1) caracteres não forem mapeados, a sequência de resultados não terminará com '*' e isso causará erro de qualquer maneira.

F=s=>/^M[^*]*\*$/.test(s=s.replace(/.../g,x=>
"KNKNTTTTRSRSIIMIQHQHPPPPRRRRLLLLEDEDAAAAGGGGVVVV*Y*YSSSS*CWCLFLF"
[[for(c of(r=0,x))r=r*4+"ACGU".search(c)]|r]))?s:'Error'

Explicado

Cada caractere em um trigêmeo pode ter 4 valores, portanto, existem exatamente 4 ^ 3 == 64 trigêmeos. A função C mapeia cada trigêmeo para um número entre 0 e 63. Nenhuma verificação de erro é necessária, pois os caracteres de entrada são apenas ACGU.

C=s=>[for(c of(r=0,s))r=r*4+"ACGU".search(c)]|r

Cada trigêmeo é mapeado para um aminoácido identificado por um único caractere. Podemos codificar isso em uma cadeia de 64 caracteres. Para obter a string, comece com o Mapa do Codon:

zz=["* UAA UAG UGA","A GCU GCC GCA GCG","C UGU UGC","D GAU GAC","E GAA GAG"
,"F UUU UUC","G GGU GGC GGA GGG","H CAU CAC","I AUU AUC AUA","K AAA AAG"
,"L UUA UUG CUU CUC CUA CUG","M AUG","N AAU AAC","P CCU CCC CCA CCG","Q CAA CAG"
,"R CGU CGC CGA CGG AGA AGG","S UCU UCC UCA UCG AGU AGC","T ACU ACC ACA ACG"
,"V GUU GUC GUA GUG","W UGG","Y UAU UAC"]
a=[],zz.map(v=>v.slice(2).split(' ').map(x=>a[C(x)]=v[0])),a.join('')

... obtendo "KNKNTTTTRSRSIIMIQHQHPPPPRRRRLLLLEDEDAAAAGGGGVVVVV * Y * YSSSS * CWCLFLF"

Portanto, podemos verificar a string de entrada e usar a mesma lógica da função C para obter o código 0..63 e, a partir do código, o aminoácido char. A função de substituição dividirá a sequência de entrada em 3 blocos de caracteres, deixando 1 ou 2 caracteres não gerenciados (que fornecerão uma sequência de resultados inválida, não terminando em '*').

Por fim, verifique se a sequência codificada é válida usando um regexp: ela deve começar com 'M', não deve conter '*' e deve terminar com '*'

Teste no console do FireBug / FireFox

;['AUGCUAG','GGGCACUAG','AUGAACGGA','AUGUAGUGA','AAAAAAA',
'AUGUUUGUUCCGUCGAAAUACCUAUGAACACGCUAA',
'AUGAGGUGUAGCUGA','AUGCCAGUCGCACGAUUAGUUCACACGCUCUUGUAA',
'AUGCUGCGGUCCUCGCAUCUAGCGUUGUGGUUAGGGUGUGUAACUUCGAGAACAGUGAGUCCCGUACCAGGUAGCAUAAUGCGAGCAAUGUCGUACGAUUCAUAG']
.forEach(c=>console.log(c,'->',F(c)))

Resultado

AUGCUAG -> Error
GGGCACUAG -> Error
AUGAACGGA -> Error
AUGUAGUGA -> Error
AAAAAAA -> Error
AUGUUUGUUCCGUCGAAAUACCUAUGAACACGCUAA -> Error
AUGAGGUGUAGCUGA -> MRCS*
AUGCCAGUCGCACGAUUAGUUCACACGCUCUUGUAA -> MPVARLVHTLL*
AUGCUGCGGUCCUCGCAUCUAGCGUUGUGGUUAGGGUGUGUAACUUCGAGAACAGUGAGUCCCGUACCAGGUAGCAUAAUGCGAGCAAUGUCGUACGAUUCAUAG -> MLRSSHLALWLGCVTSRTVSPVPGSIMRAMSYDS*
edc65
fonte
Boa ideia! Só estava pensando em fazer isso. Você chegou antes de mim!
Optimizer
8

C, 190 bytes (função)

f(char*x){int a=0,i=0,j=0,s=1;for(;x[i];i%3||(s-=(x[j++]=a-37?a-9?"KNRSIITTEDGGVVAA*Y*CLFSSQHRRLLPP"[a/2]:77:87)==42,x[j]=a=0))a=a*4+(-x[i++]/2&3);puts(*x-77||i%3||s||x[j-1]-42?"Error":x);}

199 194 bytes (programa)

a,i,j;char x[999];main(s){for(gets(x);x[i];i%3||(s-=(x[j++]=a-37?a-9?"KNRSIITTEDGGVVAA*Y*CLFSSQHRRLLPP"[a/2]:77:87)==42,x[j]=a=0))a=a*4+(-x[i++]/2&3);puts((*x-77||i%3||s||x[j-1]-42)?"Error":x);}

Economizou alguns bytes melhorando a fórmula de hash.

Aqui está um caso de teste divertido:

AUGUAUCAUGAGCUCCUUCAGUGGCAAAGACUUGACUGA --> MYHELLQWQRLD* 

Explicação

O trigêmeo de letras é convertido em um número base 4. Cada letra é hash da seguinte maneira.

x[i]       ASCII code       Hashed to (-x[i]/2&3) 
A        64+ 1  1000001            00   
G        64+ 7  1000111            01
U        64+21  1010101            10   
C        64+ 3  1000011            11

Isso fornece um número no intervalo 0..63 . A idéia agora é usar uma tabela de pesquisa semelhante à usada pelo edc65 e pelo Optimizer. No entanto, o hash é projetado para que G e A estejam próximos um do outro e U e C estejam próximos um do outro.

Observando a tabela em https://en.wikipedia.org/wiki/Genetic_code#RNA_codon_table , vemos que, com as letras ordenadas dessa maneira, geralmente o último bit pode ser ignorado. Apenas uma tabela de pesquisa de 32 caracteres é necessária, exceto em dois casos especiais.

Veja abaixo as duas primeiras letras e os aminoácidos correspondentes (onde a terceira letra é G / A e a terceira letra é U / C). As correções para os dois casos especiais que não se ajustam à tabela de 32 caracteres são codificadas.

     A/G U/C          A/G U/C            A/G U/C         A/G U/C  
AAX> K   N       AGX> R   S         AUX> I   I      ACX> T   T
GAX> E   D       GGX> G   G         GUX> V   V      GCX> A   A
UAX> *   Y       UGX> *   C         UUX> L   F      UCX> S   S
CAX> Q   H       CGX> R   R         CUX> L   L      CCX> P   P

Corrections for special cases (where last bit cannot be ignored)
AUG 001001=9 -->  M
UGG 100101=37-->  W

Código comentado

Na versão golfed, o i%3código está na posição de incremento do forsuporte, mas é movido para uma posição mais legível no código comentado.

a,i,j;char x[999];                                                             //Array x used for storing both input and output. i=input pointer, j=output pointer.
main(s){                                                                       //s is commandline string count. if no arguments, will be set to zero. Will be used to count stops.
  for(gets(x);x[i];)                                                           //Get a string, loop until end of string (zero byte) found
    a=a*4+(-x[i++]/2&3),                                                       //Hash character x[i] to a number 0-3. leftshift any value already in a and add the new value. Increment i.
    i%3||(                                                                     //if i divisible by 3,
      s-=(x[j++]=a-37?a-9?"KNRSIITTEDGGVVAA*Y*CLFSSQHRRLLPP"[a/2]:77:87)==42,  //lookup the correct value in the table. for special cases a=24 and a=32 map to 'M' and 'W' (ASCII 77 and 87). If character is '*' (ASCII42) decrement s.   
      x[j]=a=0                                                                 //reset a to 0. clear x[j] to terminate output string.                                                     
    );   
  puts((*x-77||i%3||s||x[j-1]-42)?"Error":x);                                  //if first character not M or i not divisible by 3 or number of stops not 1 or last character not * print "Error" else print amino acid chain.
}
Level River St
fonte
Se ao menos houvesse um O! Eu adicionei um caso de teste para MGENETICS*que, porque é a palavra mais temática eu poderia fazer: P
SP3000
6

CJam, 317 121 104 bytes

q3/{{"ACGU"#}%4b"KN T RS IIMI QH P R L ED A G V *Y S *CWC LF"S/{_,4\/*}%s=}%_('M=\)'*=\'*/,1=**\"Error"?

Isso ainda pode ser jogado ainda mais.

Atualizado o mecanismo de mapeamento para o usado na resposta do edc65. Mesmo tendo inventado isso sozinho, ele me venceu :)

ATUALIZAÇÃO : Encurtou o mapa da tabela de códons observando o padrão nele.

Experimente online aqui

Optimizer
fonte
Isso interrompe se a entrada for a sequência vazia.
Peter Taylor
@ PeterTaylor Uma regra que foi adicionada à sua sugestão depois que a resposta foi postada;). Vou atualizar o código em breve.
Optimizer
11
Não foi uma regra adicionada, foi um caso de teste que já era implicitamente exigido pelas regras.
Peter Taylor
3

GolfScript (103 bytes)

{)7&2/}%3/{4base'GGEDAAVVRSKNTTMIRRQHPPLLWC*YSSLF'{..'MW'?'I*'@),+=}%=}%''+.'*'/(1<'M'=*['']=*'Error'or

Demonstração online (o NB não inclui os dois maiores casos de teste porque precisa ser executado em 15 segundos).

Dissecação

Como Steve Verrill apontou na sandbox, a tabela de pesquisa pode ser reduzida para 32 elementos mais dois casos especiais. Acontece que os casos especiais envolvem caracteres ( Me Wrespectivamente), que ocorrem apenas uma vez, e com o mapeamento correto dos caracteres para a base de 4 dígitos, é possível criar a tabela de pesquisa completa de 64 elementos a partir dos 32 elementos, fazendo uma duplicata - e - tr:

'GGEDAAVVRSKNTTMIRRQHPPLLWC*YSSLF'  # 32-element lookup table
{                                   # Map over the 32 elements...
  .                                 #   Duplicate the element
  .'MW'?'I*'@),+=                   #   Apply tr/MW/I*/ to the duplicate
}%

Depois que decodificamos, a validação permite muitas abordagens. O mais curto que eu encontrei é

.'*'/       # Duplicate and split the copy around '*' retaining empty strings
(1<'M'=*    # Pull out the first string from the split (guarantee to exist even if input is
            # the empty string); if it starts with 'M' leave the rest of the split intact;
            # otherwise reduce it to the empty array
['']=       # Check whether we have ['']. If so, the split produced [prefix ''] where
            # prefix begins with 'M'. Otherwise we want an error.
*           # If we have an error case, reduce the original decoded string to ''
'Error'or   # Standard fallback mechanism
Peter Taylor
fonte
1 byte. Desafio aceito!
Optimizer
@Optimizer, uma tradução direta para o CJam economizará alguns bytes, porque possui muitos recursos relevantes.
Peter Taylor
Minha função de hash tem 57 bytes de comprimento, enquanto a sua é 52. Portanto, só consigo ver no máximo 5 bytes salvando ...
Optimizer
Estou feliz que meu comentário na caixa de areia tenha sido útil. Eu esperava que fosse possível usar o fato de que Mera um dos casos especiais para testar um início válido, mas não funcionou dessa maneira. Ainda existem 8 pares de letras idênticas nessa sequência. Gostaria de saber se eles podem ser compactados como letras minúsculas: g-->GG a-->AAetc. Se a descompressão puder ser alcançada com menos de 8 caracteres, valerá a pena.
Level River St
1

Python, 473 bytes

t={'U(A[AG]|GA)':'*','GC.':'A','UG[UC]':'C','GA[UC]':'D','GA[AG]':'E','UU[UC]':'F','GG.':'G','CA[UC]':'H','AU[UCA]':'I','AA[AG]':'K','(UU[AG]|CU.)':'L','AUG':'M','AA[UC]':'N','CC.':'P','CA[AG]':'Q','(CG.|AG[AG])':'R','(UC.|AG[UC])':'S','AC.':'T','GU.':'V','UGG':'W','UA[UC]':'Y'}
import re
i=raw_input()
a=''
for x in[i[y:y+3]for y in range(0,len(i),3)]:
 a+=[t[u]for u in t.keys()if re.match(u, x)][0]
print["Error",a][all((a[0]+a[-1]=="M*",len(i)%3==0,not"*"in a[1:-1]))]
James Williams
fonte
1

Python 2, 370 358 354 bytes

Essa é uma abordagem muito direta, sem compactação, apenas tentando compactar as informações bastante densamente:

s=lambda x:x and[x[:3]]+s(x[3:])or[]
def f(I):O=''.join(d*any(0==x.find(p)for p in e)for x in s(I)for d,e in zip('*ACDEFGHIKLMNPQRSTVWY',map(s,'UAAUAGUGA,GC,UGUUGC,GAUGAC,GAAGAG,UUUUUC,GG,CAUCAC,AUUAUCAUA,AAAAAG,UUAUUGCU,AUG,AAUAAC,CC,CAACAG,AGAAGGCG,AGUAGCUC,AC,GU,UGG,UAUUAC'.split(','))));return['Error',O][len(I)%3==0==len(O)-O.find('*')-(O[0]=='M')]

Edit: Raspou alguns caracteres seguindo a sugestão do xnor.

Emil
fonte
Eu acredito que você pode escrever smais curto recursivamente como s=lambda x:x and[x[:3]]+s(x[3:]).
Xnor
@ xnor Ótimo, eu não pensei nisso. Não funciona bem assim, porque no final da recursão ele produzirá uma sequência vazia e não uma lista vazia. Mas com mais quatro personagens, posso fazê-lo funcionar. Obrigado!
Emil
1

Scala (317 caracteres)

def g(c:Char)="ACGU"indexOf c;def h(s:String,i:Int)=g(s(i))*16+g(s(i+1))*4+g(s(i+2));def p(a:Int)=a!=48&&a!=50&&a!=56;def f(s:String)=if(s.length%3!=0||h(s,0)!=14||p(h(s,s.length-3)))"Error"else{var r="";for(i<-0 to s.length-3 by 3)r+="KNKNTTTTRSRSIIMIQHQHPPPPRRRRLLLLEDEDAAAAGGGGVVVV*Y*YSSSS*CWCLFLF"charAt h(s,i);r}

A função principal é f. Obviamente, uma melhor opção seria retornar um Option[String].

bb94
fonte
0

JavaScript (ES6), 143 bytes

s=>/^M\w*\*$/.test(s=s.replace(/.../g,c=>"PVLVLHDVLGRGRAPGR*KYNVL*KTSTSGRTSILIFYNMLR*SCTSRWEQDHIFEQPAPASC.A"[parseInt(c,36)%128%65]))?s:'Error'

Experimente online!

Arnauld
fonte