【问题标题】:clojure read large text file and count occurrencesclojure 读取大文本文件并计算出现次数
【发布时间】:2013-06-23 01:03:09
【问题描述】:

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

something
bla
error123
foo
test
error123
line
junk
error55
more
stuff

我想结束(虽然我在考虑地图,但并不关心什么数据结构)

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 和函数式编程的新手,我将不胜感激有关如何改进这一点的任何建议。 谢谢!

【问题讨论】:

    标签: clojure


    【解决方案1】:

    我想你可能正在寻找频率函数:

    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}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-08
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多