首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Clojure中使用java.io/reader时获得副作用的正确方法?

在Clojure中使用java.io/reader时获得副作用的正确方法?
EN

Stack Overflow用户
提问于 2014-04-09 20:49:37
回答 1查看 129关注 0票数 2

我正在从一个很大的文本文件中读取行。该文件包含一组数据,我希望从中选择特定的行号。我想要做的是从文件中读取一行,如果这一行是我想要的,那么将它与我的结果联系起来,如果不是,那么检查下一行。我不想把我在记忆中看到的所有行都存储起来,所以我想找一种方法,在我读到它们的时候,把它们从读者行-seq中删除。

我有这样的功能:

代码语言:javascript
复制
;; evaluates but doesn't modify the line sequence so continuously adds 
;; the same first line to the result. I would like this exact function 
;; but somehow have it drop the first line of lines at each iteration.
    (defn get-training-data [batch-size batch-num]
      (let [line-numbers (fn that returns vector of random numbers)]
        (with-open [rdr (clojure.java.io/reader "resources/sample.txt")]
          (let [lines (line-seq rdr) res []]
            (for [i (range (apply max line-numbers))
                  :let [res (conj res (json/read-str (first lines)))]
                  :when (some #{i} line-numbers)]
              res)))))

我也有这样的功能:

代码语言:javascript
复制
;;this works as I want it to, but only with a small file and produces a 
;;stack overflow with a large file
    (defn get-training-data1 [batch-size batch-num]
      (let [line-numbers (fn that returns a vector of random numbers)]
        (with-open [rdr (clojure.java.io/reader "resources/sample.txt")]
          (let [lines (line-seq rdr)]
            (loop [i 0 f (apply max line-numbers) res [] lines lines]
              (if (> i f)
                res
                (if (some #{i} line-numbers)
                  (recur
                   (inc i)
                   f
                   (conj res (json/read-str (first lines)))
                   (drop 1 lines))
                  (recur
                   (inc i)
                   f
                   res
                   (drop 1 lines)))))))))

在尝试测试时,我开发了以下更简单的案例:

代码语言:javascript
复制
;;works
(let [res []]
  (for [i (range 10)
        :let [res (conj res i)]
        :when (odd? i)]
    res)) ;;([1] [3] [5] [7] [9])

;;now an attempt to get the same result but have a side effect each time, 
;;produces null pointer exception.
(let [res []]
  (for [i (range 10)
        :let [res (conj res i)]  
        :when (odd? i)]
    (doall 
     (println i)
     res)))

我相信,如果我能想出如何在a for中产生副作用,那么第一个问题就会得到解决,因为我只会产生副作用,从而删除读者行序列的第一行。

你们有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-04-09 20:58:53

map和filter会很好地做到这一点,这样就不会在内存中存储更多的东西了。

代码语言:javascript
复制
user> (->> (line-seq (clojure.java.io/reader "project.clj")) ;; lazy sequence of lines
           (map vector (range))                              ;; add an index
           (filter #(#{1 3 7 9} (first %)))                  ;; filter by index
           (map second ))                                    ;; drop the index

("  :description \"API server for Yummly mobile app(s)\"" 
 "[com.project/example \"1.4.8-SNAPSHOT\"]" 
 "                 [org.clojure/tools.cli \"0.2\.4\"]" 
 "                 [clojurewerkz/mailer \"1.0.0-alpha3\"]")
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22973618

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档