Я пишу реализацию Clojure из this coding challenge, пытаясь найти среднюю длину записи последовательности в формате FASTA:Улучшения Clojure отложенным сло использование для итерационного разбора текста
>1
GATCGA
GTC
>2
GCA
>3
AAAAA
Для получения дополнительной информации см это related StackOverflow post о решение Эрланга.
Моя начинающая попытка 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 секунд на большой файл по сравнению до 7 секунд для реализации Python. Можете ли вы предложить какие-либо предложения по ускорению кода и повышению его интуитивности? Является ли использование lazy-seq корректным синтаксическим анализом записи файла по записи?
На самом деле я думаю, что это вполне вероятно, имеет значение с большими наборами данных ... Я даже отправил ответ, указывая на это ранее, но затем предложил смешной способ решения проблемы в мгновенном промежуток разума - +1 для правильного решения этой проблемы. –
Я думаю, что группы линий между> s должны рассматриваться как отдельные записи; что-то вроде '(partition-by # (. startsWith^String%"> "))' может помочь. Общая идея остается прежней. –
ataggart и Michal, большое спасибо за эти указатели. С ними, вот более чистая версия, которая заканчивается в 1/4 раза: http://gist.github.com/485853. Это примерно в 2 раза медленнее, чем моя версия Python, включая время запуска JVM из командной строки. Я многому учусь из этого упражнения; если есть другие видимые области для улучшения, пожалуйста, дайте мне знать, и я могу перебирать другую версию. –