函数返回迭代字符串时的Map列表,kmer计数

时间:2014-10-06 01:40:08

标签: scala

我正在创建一个用Scala编写的k-mer频率计数器(类似于Hadoop中的字数)。我对Scala很新,但我有一些编程经验。

输入是一个包含基因序列的文本文件,我的任务是获取每个k-mer的频率,其中k是序列的某个指定长度。

因此,序列AGCTTTC有三个 5-mers (AGCTT,GCTTT,CTTTC)

我已经解析了输入并创建了一个巨大的字符串,这是整个序列,新的行抛弃了k-mer计数,因为一行的序列的结尾应该仍然形成一个k-mer,其开头是下一行的序列。

现在我正在尝试编写一个函数,该函数将生成一个地图List[Map[String, Int]]列表,使用它可以很容易地使用scala的groupBy函数来获取常见k-mers的计数

import scala.io.Source

object Main {
  def main(args: Array[String]) {

    // Get all of the lines from the input file
    val input = Source.fromFile("input.txt").getLines.toArray

    // Create one huge string which contains all the lines but the first
    val lines = input.tail.mkString.replace("\n","")

    val mappedKmers: List[Map[String,Int]] = getMappedKmers(5, lines)

  }

  def getMappedKmers(k: Int, seq: String): List[Map[String, Int]] = {
    for (i <- 0 until seq.length - k) {
      Map(seq.substring(i, i+k), 1) // Map the k-mer to a count of 1
    }
  }
}

几个问题:

  • 如何创建/生成List[Map[String,Int]]
  • 你会怎么做?

绝对赞赏任何帮助和/或建议!

1 个答案:

答案 0 :(得分:4)

你非常接近 - 你的代码有三个相当小的问题。

首先,for (i <- whatever) foo(i)whatever.foreach(i => foo(i))的语法糖,这意味着你实际上并没有对whatever的内容做任何事情。你想要的是for (i <- whatever) yield foo(i),它是whatever.map(i => foo(i))的糖,并返回转换后的集合。

第二个问题是0 until seq.length - kRange,而不是List,所以即使您添加yield,结果仍然会赢得&# 39; t与声明的返回类型对齐。

第三个问题是Map(k, v)尝试使用两个键值对kv创建地图。您需要Map(k -> v)Map((k, v)),其中任何一个都明确表示您有一个参数对。

所以以下内容应该有效:

def getMappedKmers(k: Int, seq: String): IndexedSeq[Map[String, Int]] = {
  for (i <- 0 until seq.length - k) yield {
    Map(seq.substring(i, i + k) -> 1) // Map the k-mer to a count of 1
  }
}

如果您最后更喜欢列表,也可以将范围或整个结果转换为包含.toList的列表。

顺便说一下,sliding上的Seq方法完全符合您的要求,值得注意:

scala> "AGCTTTC".sliding(5).foreach(println)
AGCTT
GCTTT
CTTTC

对于真正的代码我肯定会建议类似"AGCTTTC".sliding(5).toList.groupBy(identity)的内容。