我正在创建一个k-mer频率计数器(类似于Hadoop中的单词计数),它是用Scala编写的。我对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]]
任何帮助和/或建议都是绝对感谢的!
发布于 2014-10-05 18:16:20
您已经非常接近了--您的代码有三个相当小的问题。
首先,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 - k
是一个Range
,而不是一个List
,所以即使添加了yield
,结果仍然不会与声明的返回类型一致。
第三个问题是Map(k, v)
试图用两个键值对( k
和v
)创建一个映射。您需要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)
的东西。
https://stackoverflow.com/questions/26209027
复制相似问题