clojure读取大文本文件并计算出现次数

标签 clojure

我正在尝试读取一个大文本文件并计算特定错误的出现次数。 例如,对于以下示例文本

something
bla
error123
foo
test
error123
line
junk
error55
more
stuff

我想要最终得到(虽然我正在考虑 map ,但并不真正关心什么数据结构)

error123 - 2
error55 - 1

这是我迄今为止尝试过的

(require '[clojure.java.io :as io])

(defn find-error [line]
  (if (re-find #"error" line)    
       line))


(defn read-big-file [func, filename]
 (with-open [rdr (io/reader filename)]
   (doall (map func (line-seq rdr)))))  

这样称呼

 (read-big-file find-error "sample.txt")

返回:

(nil nil "error123" nil nil "error123" nil nil "error55" nil nil)

接下来我尝试删除 nil 值和类似项目的分组

(group-by identity (remove #(= nil %) (read-big-file find-error "sample.txt")))

返回

{"error123" ["error123" "error123"], "error55" ["error55"]}

这已经接近期望的输出,尽管它可能效率不高。我现在怎样才能得到计数?另外,作为 clojure 和函数式编程的新手,我将不胜感激任何有关如何改进这一点的建议。 谢谢!

最佳答案

我认为您可能正在寻找频率函数:

user=> (doc frequencies)
-------------------------
clojure.core/frequencies
([coll])
  Returns a map from distinct items in coll to the number of times
  they appear.
nil

所以,这应该会给你你想要的:

(frequencies (remove nil? (read-big-file find-error "sample.txt")))
;;=> {"error123" 2, "error55" 1}

但是,如果您的文本文件非常大,我建议您在 line-seq 内联上执行此操作,以确保不会耗尽内存。这样,您还可以使用 filter 而不是 mapremove

(defn count-lines [pred, filename]
  (with-open [rdr (io/reader filename)]
    (frequencies (filter pred (line-seq rdr)))))

(defn is-error-line? [line]
  (re-find #"error" line))

(count-lines is-error-line? "sample.txt")
;; => {"error123" 2, "error55" 1}

关于clojure读取大文本文件并计算出现次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17256807/

相关文章:

clojure - 了解 Clojure 中以数据为中心的应用程序和对象组合

clojure - Clojure中的递归

clojure - 在 Clojure 中停止线程声音循环

clojure - Clojure 中的匿名宏

clojure - 返回第一个非空/空白值?

clojure - REPL 中的方法签名

clojure - 模式匹配或多态分派(dispatch)是否可用作 clojure 中的条件结构?

emacs - 安装 cider-nrepl

clojure - 在 clojure 中用宏捕获变量

clojure - 在并发环境中拍摄复杂可变结构的快照