从RNA到蛋白质的翻译


18

RNA和DNA一样,是在细胞中编码遗传信息的分子。它由核苷酸组成,由碱基腺嘌呤(A),胞嘧啶(C),鸟嘌呤(G)和尿嘧啶(U)表示。* 密码子是三个核苷酸的序列。

蛋白质是具有多种功能的大分子,例如在头发和指甲中发现的角蛋白和在血细胞中携带氧气的血红蛋白。它们由氨基酸组成氨基酸在RNA分子中被编码为密码子。有时,不同的密码子可能编码相同的氨基酸。每个氨基酸通常由单个字母表示,例如H代表组氨酸。

给定一个序列ACGU,可以将其翻译成相应的蛋白质字符串吗?

* DNA由ACGT组成,其中T为胸腺嘧啶。在DNA到RNA转录过程中,胸腺嘧啶被尿嘧啶替代。


输入值

输入将是仅包含ACGU大写字符的单个字符串。您可以为此挑战编写函数或完整程序。

输出量

您可以选择通过打印或返回字符串来输出(后一种选择仅在函数的情况下可用)。

翻译应该开始以起始密码子(AUG表示为M)并且结束于终止密码子(之一UAAUAGUGA表示为*)。在四种情况下,输入可能无效:

  • 输入不以起始密码子开头
  • 输入不以终止密码结尾
  • 输入的长度不是3的倍数
  • 输入的结尾处包含终止密码子

在所有这些情况下,Error都应输出。请注意,与终止密码子不同,起始密码子可能会在字符串开头之后出现。

否则,您应该通过以下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

...并输出翻译后的字符串。

例子

无效的情况:

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

有效案例:

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

编辑:添加了更多的测试用例

计分

这是代码高尔夫,所以最少字节的代码将获胜。

注意:我不是分子生物学专家,所以如果我遗漏了任何内容,请随时纠正我:)


1
合适的翻译人员应该能够找到任何字符串中的开放阅读框,而不仅仅是以AUG开头的阅读框!
canadianer 2014年

@canadianer Ahaha是的,我最初认为是这样,但我不想通过引入开放阅读框(甚至翻译单个字符串翻译多种蛋白质)使问题变得过于复杂:)
Sp3000 2014年

空字符串将是一个有用的测试用例,因为它会破坏一些方法来测试解码后的序列以M和开头*
彼得·泰勒

@PeterTaylor添加了一些简短的测试案例:)
Sp3000

1
如果您想成为一个真正的痛苦,可以使用DNA而不是RNA,因此您的阅读框架也向后。
user137 2014年

Answers:


6

CJam(97 93 92 91字节)

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

这是我的GolfScript解决方案的一个端口,其哈希函数略有调整,因为令我惊讶的是CJam没有从GolfScript借用的一件事是将字符串视为整数数组。

多亏了Optimizer的建议,节省了6个字节(包括我认为自己曾尝试但无法使用的东西中的两个字节)。


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

@Optimizer,其中有些似乎有所改善。但是,它给出了运行时错误,并且与Q而不是的比较[Q]是不正确的。
彼得·泰勒

1.您没有正确复制代码,当代码跨越注释中的多行时,在换行符处会得到一个奇怪的unicode字符。然后,您将不得不自己输入代码。2.参见逻辑,已对其进行了更改以正确工作,从而[Q]进行Q更改是正确的。
Optimizer

@Optimizer,尝试测试用例AUGUAGUGA
Peter Taylor

1
啊好吧。仍然[Q]->Qa
Optimizer

10

的JavaScript(ES6)167个177字符在UTF8编码为167个177字节

...所以我希望每个人都开心。

编辑实际上,最后一个块太短不需要特殊情况。如果未映射最后2个(或1个)字符,则结果字符串不会以'*'结尾,并且仍然会产生错误。

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'

讲解

一个三元组中的每个char可以有4个值,因此正好有4 ^ 3 == 64个三元组。C函数将每个三元组映射到0到63之间的数字。由于输入字符仅为ACGU,因此无需进行错误检查。

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

每个三联体都映射到由单个字符识别的氨基酸。我们可以将其编码为64个字符串。要获取字符串,请从密码子贴图开始:

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

...获得“ KNKNTTTTRSRSIIMIQHQHPPPPRRRRLLLEDEDAAAAGGGGVVVV * Y * YSSSS * CWCLFLF”

因此,我们可以扫描输入的字符串,并使用与C函数相同的逻辑来获取代码0..63,并从该代码获取氨基酸char。replace函数将输入字符串分成3个字符块,最终使1或2个字符不受管理(这将给出无效的结果字符串,不以'*'结尾)。

最后,使用正则表达式检查编码后的字符串是否有效:它必须以“ M”开头,不能包含“ *”并且必须以“ *”结尾

在FireBug / FireFox控制台中测试

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

输出量

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

好主意!只是想这样做。你打败我了!
Optimizer

8

C,190字节(功能)

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字节(程序)

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

通过改进哈希公式节省了几个字节。

这是一个有趣的测试用例:

AUGUAUCAUGAGCUCCUUCAGUGGCAAAGACUUGACUGA --> MYHELLQWQRLD* 

说明

字母的三元组将转换为以4为底的数字。每个字母的散列如下。

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

这给出了范围内的数字0..63。现在的想法是使用类似于edc65和Optimizer使用的查找表。但是,哈希设计为使G和A彼此相邻,而U和C彼此相邻。

查看https://en.wikipedia.org/wiki/Genetic_code#RNA_codon_table上的表,我们看到,以这种方式排序的字母通常可以忽略最后一位。除了两种特殊情况外,只需要一个32个字符的查找表。

请参见下面的前两个字母和相应的氨基酸(其中第三个字母为G / A,而第三个字母为U / C)。对不适合32个字符表的两种特殊情况的更正进行了硬编码。

     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

注释代码

在高尔夫版本中,i%3代码位于for括号的递增位置,但在注释的代码中移至更易读的位置。

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

如果只有一个O!我为此添加了一个测试用例MGENETICS*,因为它是我能做的最主题的词:P
Sp3000,2014年

6

CJam,317个121 104字节

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

仍然可以打高尔夫球。

将映射机制更新为edc65的答案中使用的映射机制。即使我自己想到了这个,他还是击败了我:)

更新:通过观察其中的模式缩短了密码子表图。

在这里在线尝试


如果输入为空字符串,则会中断。
彼得·泰勒

@PeterTaylor发布答案后在您的建议中添加的一条规则;)。我将尽快更新代码。
Optimizer

1
这不是添加的规则,而是规则已经隐式要求的测试用例。
彼得·泰勒

3

GolfScript(103字节)

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

在线演示(NB不包括两个最大的测试用例,因为它需要在15秒内运行)。

解剖

正如史蒂夫·韦里尔(Steve Verrill)在沙盒中指出的那样,查询表可以减少到32个元素加两个特殊情况。事实证明,特殊情况都涉及到仅出现一次的字符(MW分别出现),并且通过将字符正确映射到以4位为底的数字,可以通过重复执行从32个元素构建完整的64个元素的查找表-和- tr

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

然后,一旦我们完成了解码,验证就可以采用许多方法。我发现的最短的是

.'*'/       # 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个字节 接受挑战!
Optimizer

@Optimizer,直接转换为CJam会节省很多字节,因为它具有很多相关的内置函数。
彼得·泰勒

我的散列函数长为57个字节,而您的散列函数为52个。因此,我最多只能看到节省了5个字节……
Optimizer

我很高兴我在沙箱中的评论很有用。我希望有可能使用作为M特殊情况之一的事实来测试一个有效的开始,但是事实并非如此。该字符串中仍然有8对相同的字母。我想知道是否可以将它们压缩为小写字母:g-->GG a-->AA等。如果可以用8个以下的字符实现解压缩,那将是值得的。
级圣河

1

Python,473个字节

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字节

这是一种非常简单的方法,不使用压缩,只是尝试非常密集地打包信息:

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

编辑:按照xnor的建议删除了几个字符。


我相信您可以s递归地写成更短的s=lambda x:x and[x[:3]]+s(x[3:])
xnor 2014年

@xnor太好了,我没想到。它不是那样工作的,因为在递归结束时它将输出一个空字符串而不是一个空列表。但是再增加四个字符,我就可以使它工作。谢谢!
埃米尔(Emil)2014年

1

Scala(317个字符)

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}

主要功能是f。当然,更好的选择是返回Option[String]


0

JavaScript(ES6),143字节

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

在线尝试!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.