Traduction d'ARN en protéines

18

L'ARN , comme l'ADN, est une molécule trouvée dans les cellules codant pour l'information génétique. Il se compose de nucléotides , qui sont représentés par les bases adénine (A), cytosine (C), guanine (G) et uracile (U). * Un codon est une séquence de trois nucléotides.

Les protéines sont de grosses molécules qui remplissent une vaste gamme de fonctions, comme la kératine qui se trouve dans les cheveux et les ongles et l'hémoglobine qui transporte l'oxygène dans les cellules sanguines. Ils sont constitués d' acides aminés , qui sont codés en tant que codons dans les molécules d'ARN. Parfois, différents codons peuvent coder pour le même acide aminé. Chaque acide aminé est généralement représenté par une seule lettre, par exemple H représente l'histidine.

Étant donné une séquence de ACGU, pouvez-vous la traduire dans la chaîne de protéines correspondante?

* L'ADN est constitué d'ACGT, où le T est la thymine. Lors de la transcription de l'ADN en ARN, la thymine est remplacée par l'uracile.


Contribution

L'entrée sera une chaîne unique composée uniquement des caractères ACGUen majuscules. Vous pouvez écrire une fonction ou un programme complet pour ce défi.

Production

Vous pouvez choisir de sortir via l'impression ou le retour d'une chaîne (ce dernier choix n'est disponible que dans le cas d'une fonction).

La traduction devrait commencer à un codon de départ ( AUGreprésenté comme M) et se terminent à un codon stop (un UAA, UAGou UGA, comme représenté *). Il y a quatre cas où l'entrée peut être invalide:

  • L'entrée ne commence pas par un codon de démarrage
  • L'entrée ne se termine pas par un codon d'arrêt
  • La longueur de l'entrée n'est pas un multiple de 3
  • L'entrée contient un codon d'arrêt ailleurs qu'à la fin

Dans tous ces cas, Errordevrait être sorti. Notez que, contrairement aux codons d'arrêt, les codons de démarrage peuvent apparaître après le début de la chaîne.

Sinon, vous devez convertir chaque codon en son acide aminé respectif via le tableau de codon d'ARN suivant :

* 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

... et sortir la chaîne traduite.

Exemples

Cas non valides:

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

Cas valides:

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

Modifier: Ajout de plus de cas de test

Notation

C'est le code golf, donc le code dans le moins d'octets gagne.

Remarque: je ne suis pas un expert en biologie moléculaire, alors n'hésitez pas à me corriger si j'ai quelque chose d'anormal :)

Sp3000
la source
1
Un traducteur approprié devrait être capable de trouver le cadre de lecture ouvert dans n'importe quelle chaîne, pas seulement ceux qui commencent par AUG!
canadianer
@canadianer Ahaha ouais j'ai d'abord pensé à ça, mais je ne voulais pas rendre la question trop compliquée en introduisant des cadres de lecture ouverts (ou même en traduisant plusieurs protéines à partir d'une seule chaîne) :)
Sp3000
La chaîne vide serait un cas de test utile, car elle rompra certaines approches pour tester que la séquence décodée commence Met se termine par *.
Peter Taylor
@PeterTaylor Ajouté, avec quelques autres cas de test courts :)
Sp3000
1
Si vous vouliez être une vraie douleur, vous pouvez utiliser de l'ADN au lieu de l'ARN, vous avez donc aussi des cadres de lecture à l'envers.
user137

Réponses:

6

CJam ( 97 93 92 91 octets)

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

Il s'agit d'un portage de ma solution GolfScript avec une fonction de hachage légèrement modifiée car, à ma grande surprise, une chose que CJam n'a pas empruntée à GolfScript est de traiter les chaînes comme des tableaux d'entiers.

6 octets enregistrés grâce aux suggestions d' Optimizer (dont deux octets de quelque chose que je pensais avoir essayé et qui n'a pas fonctionné - hein).

Peter Taylor
la source
1
q"GACU"f#3/{4b"GGEDAAVVRSKNTTMIRRQHPPLLWC*YSSLF"{_s"MW""I*"er}%=}%s_'*/(1<"M"=*Q="Error"@?- 90
Optimizer
@Optimizer, une partie de cela semble être une amélioration. Cependant, cela donne une erreur d'exécution et la comparaison avec Qplutôt que [Q]est juste incorrecte.
Peter Taylor
1. vous n'avez pas copié le code correctement, lorsque le code s'étend sur plusieurs lignes dans les commentaires, il obtient un caractère unicode étrange au saut de ligne. Vous devrez alors taper manuellement le code vous-même. 2. Voir la logique, il a été modifié pour fonctionner correctement, donc [Q]au Qchangement est correct.
Optimizer
@Optimizer, essayez le cas de testAUGUAGUGA
Peter Taylor
1
Ah ok. Toujours [Q]->Qa
Optimizer
10

JavaScript (ES6) 167 177 caractères codés en UTF8 sous la forme de 167 177 octets

... alors j'espère que tout le monde est content.

Edit En fait, pas besoin d'un cas particulier pour le dernier bloc trop court. Si les 2 (ou 1) derniers caractères ne sont pas mappés, la chaîne de résultat ne se termine pas par '*' et cela donne quand même une erreur.

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'

Expliqué

Chaque caractère d'un triplet peut avoir 4 valeurs, il y a donc exactement 4 ^ 3 == 64 triplets. La fonction C mappe chaque triplet à un nombre compris entre 0 et 63. Aucune vérification d'erreur n'est nécessaire car les caractères d'entrée sont uniquement ACGU.

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

Chaque triplet correspond à un acide aminé identifié par un seul caractère. Nous pouvons encoder cela dans une chaîne de 64 caractères. Pour obtenir la chaîne, commencez par la carte de 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('')

... obtention "KNKNTTTTRSRSIIMIQHQHPPPPRRRRLLLLEDEDAAAAGGGGVVVV * Y * YSSSS * CWCLFLF"

Nous pouvons donc scanner la chaîne d'entrée et utiliser la même logique de la fonction C pour obtenir le code 0..63, et à partir du code le caractère aminoacide. La fonction de remplacement divisera la chaîne d'entrée en blocs de 3 caractères, laissant éventuellement 1 ou 2 caractères non gérés (ce qui donnera une chaîne de résultat non valide, ne se terminant pas par '*').

Enfin, vérifiez si la chaîne encodée est valide à l'aide d'une expression rationnelle: elle doit commencer par 'M', ne doit pas contenir '*' et doit se terminer par '*'

Test dans la console FireBug / FireFox

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

Production

AUGCUAG -> Error
GGGCACUAG -> Error
AUGAACGGA -> Error
AUGUAGUGA -> Error
AAAAAAA -> Error
AUGUUUGUUCCGUCGAAAUACCUAUGAACACGCUAA -> Error
AUGAGGUGUAGCUGA -> MRCS*
AUGCCAGUCGCACGAUUAGUUCACACGCUCUUGUAA -> MPVARLVHTLL*
AUGCUGCGGUCCUCGCAUCUAGCGUUGUGGUUAGGGUGUGUAACUUCGAGAACAGUGAGUCCCGUACCAGGUAGCAUAAUGCGAGCAAUGUCGUACGAUUCAUAG -> MLRSSHLALWLGCVTSRTVSPVPGSIMRAMSYDS*
edc65
la source
Bonne idée! Pensais juste à faire ça. Tu m'as battu!
Optimizer
8

C, 190 octets (fonction)

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 octets (programme)

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

Enregistré quelques octets en améliorant la formule de hachage.

Voici un cas de test amusant:

AUGUAUCAUGAGCUCCUUCAGUGGCAAAGACUUGACUGA --> MYHELLQWQRLD* 

Explication

Le triplet de lettres est converti en un nombre de base 4. Chaque lettre est hachée comme suit.

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

Cela donne un nombre dans la plage 0..63 . L'idée est maintenant d'utiliser une table de recherche similaire à celles utilisées par edc65 et Optimizer. Cependant, le hachage est conçu de sorte que G et A sont côte à côte et U et C sont côte à côte.

En regardant la table à https://en.wikipedia.org/wiki/Genetic_code#RNA_codon_table , nous voyons qu'avec les lettres ordonnées de cette manière, généralement le dernier bit peut être ignoré. Seule une table de recherche à 32 caractères est nécessaire, sauf dans deux cas particuliers.

Voir ci-dessous les deux premières lettres et les acides aminés correspondants (où la 3e lettre est G / A et où la 3e lettre est U / C). Les corrections pour les deux cas spéciaux qui ne correspondent pas à la table de 32 caractères sont codées en dur.

     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

Code commenté

Dans la version golfée, le i%3code est dans la position d'incrémentation du forsupport, mais il est déplacé dans une position plus lisible dans le code commenté.

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
la source
Si seulement il y en avait un O! J'ai cependant ajouté un cas de test MGENETICS*, car c'est le mot le plus thématique que j'ai pu faire: P
Sp3000
6

CJam, 317 121 104 octets

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

Cela peut encore être joué plus loin.

Mis à jour du mécanisme de mappage vers celui utilisé dans la réponse d'edc65. Même si j'ai trouvé ça tout seul, il m'a battu :)

MISE À JOUR : raccourci de la carte de la table des codons en observant le modèle qu'il contient.

Essayez-le en ligne ici

Optimiseur
la source
Cela casse si l'entrée est la chaîne vide.
Peter Taylor
@PeterTaylor Une règle qui a été ajoutée à votre suggestion après la publication de la réponse;). Je mettrai à jour le code bientôt.
Optimizer
1
Ce n'était pas une règle qui a été ajoutée, c'était un cas de test qui était déjà implicitement requis par les règles.
Peter Taylor
3

GolfScript (103 octets)

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

Démo en ligne (NB n'inclut pas les deux plus grands cas de test car il doit s'exécuter en 15 secondes).

Dissection

Comme Steve Verrill l'a souligné dans le bac à sable, la table de recherche peut être réduite à 32 éléments plus deux cas spéciaux. Il s'avère que les cas spéciaux impliquent à la fois des caractères ( Met Wrespectivement) qui n'apparaissent qu'une seule fois, et avec le bon mappage des caractères en base à 4 chiffres, il est possible de construire la table de recherche complète à 64 éléments à partir des 32 éléments en faisant une duplication -et- tr:

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

Ensuite, une fois le décodage effectué, la validation permet de nombreuses approches. Le plus court que j'ai trouvé est

.'*'/       # 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
la source
1 octet. Défi accepté!
Optimizer
@Optimizer, une traduction directe vers CJam permettra d'économiser quelques bons octets car elle contient de nombreux éléments intégrés pertinents.
Peter Taylor
Ma fonction de hachage fait 57 octets de long, tandis que la vôtre en a 52. Je ne peux donc voir que 5 octets au maximum d'économie ...
Optimizer
Je suis content que mon commentaire dans le bac à sable ait été utile. J'espérais qu'il serait possible d'utiliser le fait que Mc'était l'un des cas spéciaux pour tester un départ valide, mais cela n'a pas fonctionné de cette façon. Il y a encore 8 paires de lettres identiques dans cette chaîne. Je me demande s'ils peuvent être compressés en lettres minuscules: g-->GG a-->AAetc. Si la décompression peut être réalisée en moins de 8 caractères, cela en vaudrait la peine.
Level River St
1

Python, 473 octets

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
la source
1

Python 2, 370 358 354 octets

Il s'agit d'une approche très simple n'utilisant aucune compression, essayant simplement de regrouper les informations de manière assez dense:

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: Rasé quelques caractères suivant la suggestion de xnor.

Emil
la source
Je crois que vous pouvez écrire splus court récursivement en tant que s=lambda x:x and[x[:3]]+s(x[3:]).
2014
@xnor Super, je n'y ai pas pensé. Cela ne fonctionne pas tout à fait comme ça, car à la fin de la récursivité, il affichera une chaîne vide et non une liste vide. Mais avec quatre autres personnages, je peux le faire fonctionner. Merci!
Emil
1

Scala (317 caractères)

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 fonction principale est f. Bien sûr, un meilleur choix serait de retourner un Option[String].

bb94
la source
0

JavaScript (ES6), 143 octets

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

Essayez-le en ligne!

Arnauld
la source