【问题标题】:Converting nucleotides to amino acids using JavaScript使用 JavaScript 将核苷酸转换为氨基酸
【发布时间】:2017-09-29 05:47:25
【问题描述】:

我正在创建一个 Chrome 扩展程序,它将一串长度为 nlen 的核苷酸转换为相应的氨基酸。

我之前在 Python 中做过类似的事情,但由于我对 JavaScript 还是很陌生,我正在努力将相同的逻辑从 Python 转换为 JavaScript。我到目前为止的代码如下:

function translateInput(n_seq) {
  // code to translate goes here

  // length of input nucleotide sequence
  var nlen = n_seq.length

  // declare initially empty amino acids string
  var aa_seq = ""

  // iterate over each chunk of three characters/nucleotides
  // to match it with the correct codon
  for (var i = 0; i < nlen; i++) {




      aa_seq.concat(codon)
  }

  // return final string of amino acids   
  return aa_seq
}

我知道我想一次迭代三个字符,将它们匹配到正确的氨基酸,然后不断地将该氨基酸连接到氨基酸的输出字符串 (aa_seq),一旦循环返回该字符串完成。

我还尝试创建a dictionary 的密码子与氨基酸的关系,并想知道是否有办法使用类似的工具将三个字符密码子与其各自的氨基酸匹配:

codon_dictionary = { 
 "A": ["GCA","GCC","GCG","GCT"], 
 "C": ["TGC","TGT"], 
 "D": ["GAC", "GAT"],
 "E": ["GAA","GAG"],
 "F": ["TTC","TTT"],
 "G": ["GGA","GGC","GGG","GGT"],
 "H": ["CAC","CAT"],
 "I": ["ATA","ATC","ATT"],
 "K": ["AAA","AAG"],
 "L": ["CTA","CTC","CTG","CTT","TTA","TTG"],
 "M": ["ATG"],
 "N": ["AAC","AAT"],
 "P": ["CCA","CCC","CCG","CCT"],
 "Q": ["CAA","CAG"],
 "R": ["AGA","AGG","CGA","CGC","CGG","CGT"],
 "S": ["AGC","AGT","TCA","TCC","TCG","TCT"],
 "T": ["ACA","ACC","ACG","ACT"],
 "V": ["GTA","GTC","GTG","GTT"],
 "W": ["TGG"],
 "Y": ["TAC","TAT"],
};

编辑: 核苷酸输入字符串的一个示例是“AAGCATAGAAATCGAGGG”,对应的输出字符串“KHRNRG”。希望这会有所帮助!

【问题讨论】:

  • 也许你可以提供一个输入和输出的例子?
  • 什么是输入字符串的好例子,以及所需输出的例子?
  • This website would like access to your genetic code. Allow?
  • 刚刚更新了我的帖子以添加示例。

标签: javascript dna-sequence genetics


【解决方案1】:

意见

我个人建议的第一件事是建立一个从 3 字符密码子到氨基的字典。这将允许您的程序获取多个密码子字符串链并将它们转换为氨基字符串,而无需每次都进行昂贵的深度查找。字典会像这样工作

codonDict['GCA'] // 'A'
codonDict['TGC'] // 'C'
// etc

从那里,我实现了两个实用函数:slideslideStr。这些并不是特别重要,所以我将通过几个输入和输出示例来介绍它们。

slide (2,1) ([1,2,3,4])
// [[1,2], [2,3], [3,4]]

slide (2,2) ([1,2,3,4])
// [[1,2], [3,4]]

slideStr (2,1) ('abcd')
// ['ab', 'bc', 'cd']

slideStr (2,2) ('abcd')
// ['ab', 'cd']

我们可以使用反向字典和通用实用程序函数,编写codon2amino 是轻而易举的事

// codon2amino :: String -> String
const codon2amino = str =>
  slideStr(3,3)(str)
    .map(c => codonDict[c])
    .join('')

可运行演示

为了澄清,我们在aminoDict 的基础上构建codonDict 一次,并将其重新用于每次密码子到氨基的计算。

// your original data renamed to aminoDict
const aminoDict = { 'A': ['GCA','GCC','GCG','GCT'], 'C': ['TGC','TGT'], 'D': ['GAC', 'GAT'], 'E': ['GAA','GAG'], 'F': ['TTC','TTT'], 'G': ['GGA','GGC','GGG','GGT'], 'H': ['CAC','CAT'], 'I': ['ATA','ATC','ATT'], 'K': ['AAA','AAG'], 'L': ['CTA','CTC','CTG','CTT','TTA','TTG'], 'M': ['ATG'], 'N': ['AAC','AAT'], 'P': ['CCA','CCC','CCG','CCT'], 'Q': ['CAA','CAG'], 'R': ['AGA','AGG','CGA','CGC','CGG','CGT'], 'S': ['AGC','AGT','TCA','TCC','TCG','TCT'], 'T': ['ACA','ACC','ACG','ACT'], 'V': ['GTA','GTC','GTG','GTT'], 'W': ['TGG'], 'Y': ['TAC','TAT'] };

// codon dictionary derived from aminoDict
const codonDict =
 Object.keys(aminoDict).reduce((dict, a) =>
   Object.assign(dict, ...aminoDict[a].map(c => ({[c]: a}))), {})

// slide :: (Int, Int) -> [a] -> [[a]]
const slide = (n,m) => xs => {
  if (n > xs.length)
    return []
  else
    return [xs.slice(0,n), ...slide(n,m) (xs.slice(m))]
}

// slideStr :: (Int, Int) -> String -> [String]
const slideStr = (n,m) => str =>
  slide(n,m) (Array.from(str)) .map(s => s.join(''))

// codon2amino :: String -> String
const codon2amino = str =>
  slideStr(3,3)(str)
    .map(c => codonDict[c])
    .join('')

console.log(codon2amino('AAGCATAGAAATCGAGGG'))
// KHRNRG

进一步说明

你能澄清一下这些变量应该代表什么吗? (n、m、xs、c 等)

我们的slide 函数为我们提供了一个数组上的滑动窗口。它需要两个窗口参数——n 窗口大小和m 步长——还有一个参数是要遍历的项目数组——xs,可以读取为x's ,或复数 x,如 x 项目的集合

slide 是有目的地通用的,因为它可以在任何 iterable xs 上工作。这意味着它可以与 Array、String 或任何其他实现 Symbol.iterator 的东西一起使用。这也是我们使用像 xs 这样的通用名称的原因,因为将其命名为特定的名称会让我们认为它只能与特定类型一起使用

诸如.map(c =&gt; codonDict[c]) 中的变量c 之类的其他内容并不特别重要——我将其命名为c 代表密码子,但我们可以将其命名为xfoo ,没关系。理解c的“诀窍”就是理解.map

[1,2,3,4,5].map(c => f(c))
// [f(1), f(2), f(3), f(4), f(5)]

所以实际上我们在这里所做的只是获取一个数组 ([1 2 3 4 5]) 并创建一个新数组,我们为原始数组中的每个元素调用 f

现在,当我们查看 .map(c =&gt; codonDict[c]) 时,我们知道我们所做的只是在 codonDict 中查找每个元素的 c

const codon2amino = str =>
  slideStr(3,3)(str)          // [ 'AAG', 'CAT', 'AGA', 'AAT', ...]
    .map(c => codonDict[c])   // [ codonDict['AAG'], codonDict['CAT'], codonDict['AGA'], codonDict['AAT'], ...]
    .join('')                 // 'KHRN...'

另外,这些 'const' 项是否能够从根本上取代我原来的 translateInput() 函数?

如果您不熟悉 ES6 (ES2015),上面使用的一些语法可能会让您觉得陌生。

// foo using traditional function syntax
function foo (x) { return x + 1 }

// foo as an arrow function
const foo = x => x + 1

简而言之,是的,codon2amino 是您的 translateInput 的完全替代品,只是使用 const 绑定和箭头函数定义的。我选择了codon2amino 作为名称,因为它更好地描述了函数的操作——translateInput 没有说明它的翻译方式(A 到 B,或 B 到 A?),以及 “输入” em> 在这里是一种毫无意义的描述符,因为所有函数都可以接受输入。

您看到其他 const 声明的原因是因为我们将您的函数的工作拆分为多个函数。造成这种情况的原因大多超出了这个答案的范围,但简单的解释是,一个承担多项任务的专门功能对我们来说不如可以以合理方式组合/重用的多个通用功能有用.

当然,codon2amino 需要查看输入字符串中的每个 3 字母序列,但这并不意味着我们必须在 codon2amino 函数中编写字符串拆分代码。我们可以像使用slideStr 一样编写一个通用的字符串拆分函数,这对于任何想要遍历字符串序列然后让我们的codon2amino 函数使用它的函数都很有用——如果我们将所有字符串拆分代码封装在里面在codon2amino 中,下次我们需要遍历字符串序列时,我们必须复制那部分代码。


说了这么多..

有什么方法可以在保持原始 for 循环结构的同时做到这一点?

我真的认为您应该花一些时间逐步浏览上面的代码,看看它是如何工作的。如果您还没有看到以这种方式分离程序问题,那么您可以在那里学习很多宝贵的经验。

当然,这不是解决您的问题的唯一方法。我们可以使用原始的for 循环。对我来说,考虑创建迭代器i 并手动递增i++i += 3,确保检查i &lt; str.length,重新分配返回值result += something 等,会产生更多的精神开销——添加更多变量和你的大脑很快变成了汤。

function makeCodonDict (aminoDict) {
  let result = {}
  for (let k of Object.keys(aminoDict))
    for (let a of aminoDict[k])
      result[a] = k
  return result
}

function translateInput (dict, str) {
  let result = ''
  for (let i = 0; i < str.length; i += 3)
    result += dict[str.substr(i,3)]
  return result
}

const aminoDict = { 'A': ['GCA','GCC','GCG','GCT'], 'C': ['TGC','TGT'], 'D': ['GAC', 'GAT'], 'E': ['GAA','GAG'], 'F': ['TTC','TTT'], 'G': ['GGA','GGC','GGG','GGT'], 'H': ['CAC','CAT'], 'I': ['ATA','ATC','ATT'], 'K': ['AAA','AAG'], 'L': ['CTA','CTC','CTG','CTT','TTA','TTG'], 'M': ['ATG'], 'N': ['AAC','AAT'], 'P': ['CCA','CCC','CCG','CCT'], 'Q': ['CAA','CAG'], 'R': ['AGA','AGG','CGA','CGC','CGG','CGT'], 'S': ['AGC','AGT','TCA','TCC','TCG','TCT'], 'T': ['ACA','ACC','ACG','ACT'], 'V': ['GTA','GTC','GTG','GTT'], 'W': ['TGG'], 'Y': ['TAC','TAT'] };
const codonDict = makeCodonDict(aminoDict)

const codons = 'AAGCATAGAAATCGAGGG'
const aminos = translateInput(codonDict, codons)
console.log(aminos) // KHRNRG

【讨论】:

  • 我知道这总体上是如何工作的,但是您能否澄清其中一些变量应该代表什么? (n、m、xs、c 等)。另外,这些 'const' 项是否能够从根本上取代我原来的 translateInput() 函数?
  • 有什么办法可以在保持原来的 for 循环结构的同时做到这一点?
  • @happy,我大部分时间都在等待,但我会在今晚晚些时候修改答案^_^
  • 提前致谢!这几天我一直在和这段代码作斗争,这太让人抓狂了。
  • @happy,我编辑了答案以解释我编写的一些功能代码,但还包括使用原始 for 循环的函数的程序样式版本
【解决方案2】:

此外,您可以将上述答案 (@guest271314) 写成紧凑的形式:

var res = ''
str.match(/.{1,3}/g).forEach(s => {
    var key = Object.keys(codon_dictionary).filter(x => codon_dictionary[x].filter(y => y === s).length > 0)[0]
    res += key != undefined ? key : ''
})

你可以在下面看到完整的答案。

const codon_dictionary = { 
 "A": ["GCA","GCC","GCG","GCT"], 
 "C": ["TGC","TGT"], 
 "D": ["GAC", "GAT"],
 "E": ["GAA","GAG"],
 "F": ["TTC","TTT"],
 "G": ["GGA","GGC","GGG","GGT"],
 "H": ["CAC","CAT"],
 "I": ["ATA","ATC","ATT"],
 "K": ["AAA","AAG"],
 "L": ["CTA","CTC","CTG","CTT","TTA","TTG"],
 "M": ["ATG"],
 "N": ["AAC","AAT"],
 "P": ["CCA","CCC","CCG","CCT"],
 "Q": ["CAA","CAG"],
 "R": ["AGA","AGG","CGA","CGC","CGG","CGT"],
 "S": ["AGC","AGT","TCA","TCC","TCG","TCT"],
 "T": ["ACA","ACC","ACG","ACT"],
 "V": ["GTA","GTC","GTG","GTT"],
 "W": ["TGG"],
 "Y": ["TAC","TAT"],
};

const str = "AAGCATAGAAATCGAGGG";

let res = "";
// just rewrite the above code into the short answer
str.match(/.{1,3}/g).forEach(s => {
    var key = Object.keys(codon_dictionary).filter(x => codon_dictionary[x].filter(y => y === s).length > 0)[0]
    res += key != undefined ? key : ''
})

console.log(res);

【讨论】:

    【解决方案3】:

    嗯,我建议首先改变你的字典的形状——那样不是很有用,所以让我们这样做:

    const dict = { 
     "A": ["GCA","GCC","GCG","GCT"], 
     "C": ["TGC","TGT"], 
     "D": ["GAC", "GAT"],
     "E": ["GAA","GAG"],
     "F": ["TTC","TTT"],
     "G": ["GGA","GGC","GGG","GGT"],
     "H": ["CAC","CAT"],
     "I": ["ATA","ATC","ATT"],
     "K": ["AAA","AAG"],
     "L": ["CTA","CTC","CTG","CTT","TTA","TTG"],
     "M": ["ATG"],
     "N": ["AAC","AAT"],
     "P": ["CCA","CCC","CCG","CCT"],
     "Q": ["CAA","CAG"],
     "R": ["AGA","AGG","CGA","CGC","CGG","CGT"],
     "S": ["AGC","AGT","TCA","TCC","TCG","TCT"],
     "T": ["ACA","ACC","ACG","ACT"],
     "V": ["GTA","GTC","GTG","GTT"],
     "W": ["TGG"],
     "Y": ["TAC","TAT"],
    }
    const codons = Object.keys(dict).reduce((a, b) => {dict[b].forEach(v => a[v] = b); return a}, {})
    
    //In practice, you will get:
    
    const codons = { GCA: 'A',
      GCC: 'A',
      GCG: 'A',
      GCT: 'A',
      TGC: 'C',
      TGT: 'C',
      GAC: 'D',
      GAT: 'D',
      GAA: 'E',
      GAG: 'E',
      TTC: 'F',
      TTT: 'F',
      GGA: 'G',
      GGC: 'G',
      GGG: 'G',
      GGT: 'G',
      CAC: 'H',
      CAT: 'H',
      ATA: 'I',
      ATC: 'I',
      ATT: 'I',
      AAA: 'K',
      AAG: 'K',
      CTA: 'L',
      CTC: 'L',
      CTG: 'L',
      CTT: 'L',
      TTA: 'L',
      TTG: 'L',
      ATG: 'M',
      AAC: 'N',
      AAT: 'N',
      CCA: 'P',
      CCC: 'P',
      CCG: 'P',
      CCT: 'P',
      CAA: 'Q',
      CAG: 'Q',
      AGA: 'R',
      AGG: 'R',
      CGA: 'R',
      CGC: 'R',
      CGG: 'R',
      CGT: 'R',
      AGC: 'S',
      AGT: 'S',
      TCA: 'S',
      TCC: 'S',
      TCG: 'S',
      TCT: 'S',
      ACA: 'T',
      ACC: 'T',
      ACG: 'T',
      ACT: 'T',
      GTA: 'V',
      GTC: 'V',
      GTG: 'V',
      GTT: 'V',
      TGG: 'W',
      TAC: 'Y',
      TAT: 'Y' }
    
    //Now we are reasoning!
    
    //From here on, it is pretty straightforward:
    
    const rnaParser = s => s.match(/.{3}/g).map(fragment => codons[fragment]).join("")
    

    【讨论】:

      【解决方案4】:

      您可以使用for循环、String.prototype.slice()从字符串for..of循环、Object.entries()的开头一次迭代字符串三个字符以迭代codon_dictionary对象、Array.prototype.includes()的属性和值以匹配输入字符串的当前三个字符部分到设置为 codon_dictionary 对象值的数组,将属性连接到字符串变量。

      const codon_dictionary = { 
       "A": ["GCA","GCC","GCG","GCT"], 
       "C": ["TGC","TGT"], 
       "D": ["GAC", "GAT"],
       "E": ["GAA","GAG"],
       "F": ["TTC","TTT"],
       "G": ["GGA","GGC","GGG","GGT"],
       "H": ["CAC","CAT"],
       "I": ["ATA","ATC","ATT"],
       "K": ["AAA","AAG"],
       "L": ["CTA","CTC","CTG","CTT","TTA","TTG"],
       "M": ["ATG"],
       "N": ["AAC","AAT"],
       "P": ["CCA","CCC","CCG","CCT"],
       "Q": ["CAA","CAG"],
       "R": ["AGA","AGG","CGA","CGC","CGG","CGT"],
       "S": ["AGC","AGT","TCA","TCC","TCG","TCT"],
       "T": ["ACA","ACC","ACG","ACT"],
       "V": ["GTA","GTC","GTG","GTT"],
       "W": ["TGG"],
       "Y": ["TAC","TAT"],
      };
      
      const [entries, n] = [Object.entries(codon_dictionary), 3];
      
      let [str, res] = ["AAGCATAGAAATCGAGGG", ""];
      
      for (let i = 0; i + n <= str.length; i += n)
        for (const [key, prop, curr = str.slice(i, i + n)] of entries) 
          if (prop.includes(curr)) {res +=  key; break;};
      
      console.log(res);

      【讨论】:

      • 代码 sn-p 在我尝试运行时抛出错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-07
      • 1970-01-01
      • 2018-04-12
      • 1970-01-01
      相关资源
      最近更新 更多