Traduzione da RNA a proteine


18

L'RNA , come il DNA, è una molecola presente nelle cellule che codificano le informazioni genetiche. È costituita da nucleotidi , che sono rappresentati dalle basi adenina (A), citosina (C), guanina (G) e uracile (U). * Un codone è una sequenza di tre nucleotidi.

Le proteine sono grandi molecole che svolgono una vasta gamma di funzioni, come la cheratina che si trova nei capelli e nelle unghie e nell'emoglobina che trasporta l'ossigeno nelle cellule del sangue. Sono costituiti da aminoacidi , codificati come codoni nelle molecole di RNA. A volte codoni diversi possono codificare per lo stesso aminoacido. Ogni amminoacido è comunemente rappresentato da una singola lettera, ad esempio H sta per istidina.

Data una sequenza di ACGU, puoi tradurla nella corrispondente stringa proteica?

* Il DNA è costituito da ACGT, dove la T è timina. Durante la trascrizione da DNA a RNA, la timina viene sostituita dall'uracile.


Ingresso

L'input sarà una singola stringa composta solo da caratteri ACGUmaiuscoli. Puoi scrivere una funzione o un programma completo per questa sfida.

Produzione

È possibile scegliere di stampare tramite o stampando o restituendo una stringa (quest'ultima scelta è disponibile solo nel caso di una funzione).

La traduzione dovrebbe iniziare da un codone iniziale ( AUG, rappresentato come M) e terminare da un codone di arresto (uno di UAA, UAGo UGA, rappresentato da *). Esistono quattro casi in cui l'input potrebbe non essere valido:

  • L'input non inizia con un codone iniziale
  • L'ingresso non termina con un codone di arresto
  • La lunghezza dell'input non è un multiplo di 3
  • L'ingresso contiene un codone di arresto in un punto diverso da quello alla fine

In tutti questi casi, Errordovrebbe essere emesso. Si noti che, a differenza dei codoni di arresto, i codoni di avvio potrebbero apparire dopo l'inizio della stringa.

Altrimenti, è necessario convertire ciascun codone nel rispettivo aminoacido tramite la seguente tabella di codoni 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 genera la stringa tradotta.

Esempi

Casi non validi:

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

Casi validi:

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

Modifica: aggiunti altri casi di test

punteggio

Questo è il codice golf, quindi vince il codice nel minor numero di byte.

Nota: non sono un esperto di biologia molecolare, quindi sentiti libero di correggermi se ho sbagliato a capire qualcosa :)


1
Un traduttore corretto dovrebbe essere in grado di trovare il frame di lettura aperto in qualsiasi stringa, non solo quelli che iniziano con AUG!
canadese

@canadianer Ahaha sì, inizialmente l'ho considerato, ma non volevo rendere la domanda troppo complicata introducendo frame di lettura aperti (o anche traducendo più proteine ​​da una singola stringa) :)
Sp3000,

La stringa vuota sarebbe un utile test case, perché interromperà alcuni approcci per verificare che la sequenza decodificata inizi con Me finisca con *.
Peter Taylor,

@PeterTaylor Aggiunto, insieme ad alcuni altri casi di test brevi :)
Sp3000

1
Se vuoi essere un vero dolore, potresti usare il DNA al posto dell'RNA, quindi hai anche i frame di lettura all'indietro.
user137

Risposte:


6

CJam ( 97 93 92 91 byte)

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

Questa è una porta della mia soluzione GolfScript con una funzione hash leggermente ottimizzata perché con mia sorpresa una cosa che CJam non ha preso in prestito da GolfScript sta trattando le stringhe come matrici di numeri interi.

6 byte salvati grazie ai suggerimenti di Optimizer (inclusi due byte da qualcosa che pensavo di aver provato e di non aver funzionato - eh).


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

@Optimizer, in parte sembra essere un miglioramento. Tuttavia, genera un errore di runtime e il confronto Qpiuttosto che [Q]è semplicemente errato.
Peter Taylor,

1. non hai copiato correttamente il codice, quando il codice si estende su più righe nei commenti, ottiene uno strano carattere unicode all'interruzione di riga. Quindi dovrai digitare manualmente il codice da solo. 2. Vedere la logica, è stato modificato per funzionare correttamente, quindi [Q]al Qcambiamento è corretta.
Ottimizzatore

@Optimizer, prova il caso di testAUGUAGUGA
Peter Taylor,

1
Ah ok. Ancora [Q]->Qa
Ottimizzatore

10

JavaScript (ES6) 167 177 caratteri codificati in UTF8 come 167 177 byte

... quindi spero che tutti siano felici.

Modifica In effetti, non è necessario un caso speciale per l'ultimo blocco troppo corto. Se gli ultimi 2 (o 1) caratteri non sono mappati, la stringa del risultato non termina con '*' e ciò dà comunque errore.

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'

spiegato

Ogni carattere in una terzina può avere 4 valori, quindi ci sono esattamente 4 ^ 3 == 64 terzine. La funzione C associa ogni tripletta a un numero compreso tra 0 e 63. Non è necessario alcun controllo degli errori poiché i caratteri di input sono solo ACGU.

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

Ogni tripletta si associa a un aminoacido identificato da un singolo carattere. Possiamo codificarlo in una stringa di 64 caratteri. Per ottenere la stringa, inizia con la mappa dei codoni:

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('')

... ottenendo "KNKNTTTTRSRSIIMIQHQHPPPPRRRRLLLLEDEDAAAAGGGGVVVV * Y * YSSSS * CWCLFLF"

Quindi possiamo scansionare la stringa di input e usare la stessa logica della funzione C per ottenere il codice 0..63 e dal codice il carattere aminoacido. La funzione di sostituzione dividerà la stringa di input in 3 blocchi di caratteri, alla fine lasciando 1 o 2 caratteri non gestiti (che fornirà una stringa di risultato non valida, senza terminare con '*').

Alla fine, controlla se la stringa codificata è valida usando una regexp: deve iniziare con 'M', non deve contenere '*' e deve finire con '*'

Test nella console FireBug / FireFox

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

Produzione

AUGCUAG -> Error
GGGCACUAG -> Error
AUGAACGGA -> Error
AUGUAGUGA -> Error
AAAAAAA -> Error
AUGUUUGUUCCGUCGAAAUACCUAUGAACACGCUAA -> Error
AUGAGGUGUAGCUGA -> MRCS*
AUGCCAGUCGCACGAUUAGUUCACACGCUCUUGUAA -> MPVARLVHTLL*
AUGCUGCGGUCCUCGCAUCUAGCGUUGUGGUUAGGGUGUGUAACUUCGAGAACAGUGAGUCCCGUACCAGGUAGCAUAAUGCGAGCAAUGUCGUACGAUUCAUAG -> MLRSSHLALWLGCVTSRTVSPVPGSIMRAMSYDS*

Bella idea! Stavo solo pensando di farlo. Mi hai battuto sul tempo!
Ottimizzatore

8

C, 190 byte (funzione)

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 byte (programma)

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);}

Risparmio di pochi byte migliorando la formula hash.

Ecco un divertente test case:

AUGUAUCAUGAGCUCCUUCAGUGGCAAAGACUUGACUGA --> MYHELLQWQRLD* 

Spiegazione

La tripletta di lettere viene convertita in un numero di base 4. Ogni lettera è cancellata come segue.

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

Questo dà un numero nell'intervallo 0..63. L'idea ora è quella di utilizzare una tabella di ricerca simile a quelle utilizzate da edc65 e Optimizer. Tuttavia, l'hash è progettato in modo che G e A siano uno accanto all'altro e U e C siano uno accanto all'altro.

Guardando la tabella su https://en.wikipedia.org/wiki/Genetic_code#RNA_codon_table , vediamo che con le lettere ordinate in questo modo, generalmente l'ultimo bit può essere ignorato. È necessaria solo una tabella di ricerca di 32 caratteri, tranne in due casi speciali.

Vedi sotto le prime due lettere e gli amminoacidi corrispondenti (dove la terza lettera è G / ​​A e dove la terza lettera è U / C). Le correzioni per i due casi speciali che non si adattano alla tabella di 32 caratteri sono codificate.

     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

Codice commentato

Nella versione golfata il i%3codice si trova nella posizione di incremento della forparentesi, ma viene spostato in una posizione più leggibile nel codice commentato.

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.
}

Se solo ci fosse un O! Ho aggiunto un caso di prova MGENETICS*, però, perché è la parola più tematica che potrei fare: P
Sp3000,

6

CJam, 317 121 104 byte

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

Questo può ancora essere golfato ulteriormente.

Aggiornato il meccanismo di mappatura a quello usato nella risposta di edc65. Anche se me ne sono inventato da solo, mi ha battuto :)

AGGIORNAMENTO : abbreviata la mappa della tabella dei codoni osservando il modello in essa contenuto.

Provalo online qui


Ciò si interrompe se l'input è la stringa vuota.
Peter Taylor,

@PeterTaylor Una regola che è stata aggiunta al tuo suggerimento dopo che la risposta è stata pubblicata;). Aggiornerò presto il codice.
Ottimizzatore

1
Non è stata aggiunta una regola, era un caso di prova che era già implicitamente richiesto dalle regole.
Peter Taylor,

3

GolfScript (103 byte)

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

Demo online (NB non include i due casi di test più grandi perché deve essere eseguito in 15 secondi).

Dissezione

Come ha sottolineato Steve Verrill nella sandbox, la tabella di ricerca può essere ridotta a 32 elementi più due casi speciali. Si scopre che i casi speciali riguardano entrambi i caratteri ( Me Wrispettivamente) che si verificano solo una volta, e con la corretta mappatura dei caratteri sulla base di 4 cifre è possibile creare la tabella di ricerca completa a 64 elementi dai 32 elementi facendo un duplicato -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
}%

Quindi, una volta effettuata la decodifica, la convalida consente molti approcci. Il più corto che ho trovato è

.'*'/       # 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

1 byte. Sfida accettata!
Ottimizzatore

@Optimizer, una traduzione diretta in CJam salverà alcuni byte buoni perché ha molti incorporati rilevanti.
Peter Taylor,

La mia funzione di hashing è lunga 57 byte, mentre la tua è 52. Quindi posso vedere solo un massimo di 5 byte salvando ...
Ottimizzatore

Sono contento che il mio commento nella sandbox sia stato utile. Speravo che fosse possibile utilizzare il fatto che Mera uno dei casi speciali per testare un inizio valido, ma non ha funzionato in questo modo. Ci sono ancora 8 coppie di lettere identiche in quella stringa. Mi chiedo se possono essere compressi come lettere minuscole: g-->GG a-->AAecc. Se la decompressione può essere raggiunta in meno di 8 caratteri, varrebbe la pena.
Level River St

1

Python, 473 byte

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]))]

1

Python 2, 370 358 354 byte

Questo è un approccio molto diretto che non utilizza alcuna compressione, cercando solo di comprimere le informazioni abbastanza 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')]

Modifica: rasato alcuni caratteri seguendo il suggerimento di xnor.


Credo che tu possa scrivere spiù breve in modo ricorsivo come s=lambda x:x and[x[:3]]+s(x[3:]).
xnor

@xnor Fantastico, non ci ho pensato. Non funziona in questo modo, perché alla fine della ricorsione produrrà una stringa vuota e non un elenco vuoto. Ma con altri quattro personaggi posso farlo funzionare. Grazie!
Emil,

1

Scala (317 caratteri)

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}

La funzione principale è f. Naturalmente, una scelta migliore sarebbe quella di restituire un Option[String].


0

JavaScript (ES6), 143 byte

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

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.