【发布时间】:2010-07-21 21:02:47
【问题描述】:
我正在编写 this coding challenge 的 Clojure 实现,试图找到 Fasta 格式的序列记录的平均长度:
>1
GATCGA
GTC
>2
GCA
>3
AAAAA
有关更多背景信息,请参阅related StackOverflow post 关于 Erlang 解决方案。
我的 Clojure 初学者尝试使用lazy-seq 尝试一次读取文件一条记录,以便将其扩展到大文件。然而,它相当消耗内存并且速度很慢,所以我怀疑它没有以最佳方式实现。这是一个使用BioJava 库来抽象解析记录的解决方案:
(import '(org.biojava.bio.seq.io SeqIOTools))
(use '[clojure.contrib.duck-streams :only (reader)])
(defn seq-lengths [seq-iter]
"Produce a lazy collection of sequence lengths given a BioJava StreamReader"
(lazy-seq
(if (.hasNext seq-iter)
(cons (.length (.nextSequence seq-iter)) (seq-lengths seq-iter)))))
(defn fasta-to-lengths [in-file seq-type]
"Use BioJava to read a Fasta input file as a StreamReader of sequences"
(seq-lengths (SeqIOTools/fileToBiojava "fasta" seq-type (reader in-file))))
(defn average [coll]
(/ (reduce + coll) (count coll)))
(when *command-line-args*
(println
(average (apply fasta-to-lengths *command-line-args*))))
以及没有外部库的等效方法:
(use '[clojure.contrib.duck-streams :only (read-lines)])
(defn seq-lengths [lines cur-length]
"Retrieve lengths of sequences in the file using line lengths"
(lazy-seq
(let [cur-line (first lines)
remain-lines (rest lines)]
(if (= nil cur-line) [cur-length]
(if (= \> (first cur-line))
(cons cur-length (seq-lengths remain-lines 0))
(seq-lengths remain-lines (+ cur-length (.length cur-line))))))))
(defn fasta-to-lengths-bland [in-file seq-type]
; pop off first item since it will be everything up to the first >
(rest (seq-lengths (read-lines in-file) 0)))
(defn average [coll]
(/ (reduce + coll) (count coll)))
(when *command-line-args*
(println
(average (apply fasta-to-lengths-bland *command-line-args*))))
当前的实现需要 44 秒处理大文件,而 Python 实现需要 7 秒。您能否就加快代码速度并使其更直观提供任何建议?使用lazy-seq 是否按预期正确解析文件记录?
【问题讨论】:
标签: clojure lazy-evaluation bioinformatics