Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File io 从文件读取时拆分clojure中的行_File Io_Clojure_Split - Fatal编程技术网

File io 从文件读取时拆分clojure中的行

File io 从文件读取时拆分clojure中的行,file-io,clojure,split,File Io,Clojure,Split,我正在学校学习clojure,我马上就要考试了。我只是在做一些事情,以确保我掌握了窍门 我正试图逐行读取文件,正如我所做的那样,每当有“;”时,我都要拆分该行 这是到目前为止我的代码 (defn readFile [] (map (fn [line] (clojure.string/split line #";")) (with-open [rdr (reader "C:/Users/Rohil/Documents/work.txt.txt")] (doseq [line (li

我正在学校学习clojure,我马上就要考试了。我只是在做一些事情,以确保我掌握了窍门

我正试图逐行读取文件,正如我所做的那样,每当有“;”时,我都要拆分该行

这是到目前为止我的代码

(defn readFile []
  (map (fn [line] (clojure.string/split line #";"))
  (with-open [rdr (reader "C:/Users/Rohil/Documents/work.txt.txt")]
    (doseq [line (line-seq rdr)]
      (clojure.string/split line #";")
        (println line)))))
当我这样做时,我仍然会得到输出:

"I;Am;A;String;"

我错过了什么吗;DR拥抱REPL,拥抱不变性

你的问题是“我遗漏了什么?”对此,我想说你遗漏了Clojure最好的功能之一,REPL

编辑:您可能还缺少Clojure使用不可变数据结构

考虑以下代码片段:

(doseq [x [1 2 3]]
   (inc x)
   (prn x))
(doseq [x [1 2 3]] (prn (inc x)))
此代码不打印“2 3 4”

它打印“1 2 3”,因为x不是可变变量

在第一次迭代中,
(inc x)
被调用,返回2,由于没有传递给任何对象,因此被丢弃,然后
(prn x)
打印x的值,该值仍然是1

现在考虑这个代码片段:

(doseq [x [1 2 3]]
   (inc x)
   (prn x))
(doseq [x [1 2 3]] (prn (inc x)))
在第一次迭代中,inc将其返回值传递给prn,因此得到2

长示例:

我不想剥夺你自己解决问题的机会,所以我将用一个不同的问题作为例子

给定文件“birds.txt” 使用数据
“1chicken\n2duck\n3larry”
您需要编写一个函数,该函数接受一个文件并返回一系列鸟名

让我们将此问题分解为更小的块:

首先让我们读取文件并将其拆分为行

(slurp“birds.txt”)
将为整个文件提供一个字符串

clojure.string/split line
将为我们提供一个集合,其中每一行作为集合中的一个元素

(clojure.string/split-lines(slurp“birds.txt”)
让我们
[“chicken”“2duck”“3Larry”]

此时,我们可以在该集合上映射一些函数,以去除数字,如
(map#(clojure.string/replace%#“\d”“”)birds集合)

或者,当整个文件是一个字符串时,我们可以将这一步骤向上移动

现在我们已经有了所有的片段,我们可以将它们放在一个功能管道中,其中一个片段的结果将输入下一个片段

在Clojure中,有一个很好的宏使其更具可读性,即
->

它接受一次计算的结果,并将其作为第一个参数注入下一次计算

因此,我们的管道如下所示:

(-> "C:/birds.txt"
     slurp
     (clojure.string/replace #"\d" "") 
     clojure.string/split-lines)
(ns tst.demo.core
  (:use tupelo.test)
  (:require [tupelo.core :as t]
            [clojure.string :as str] ))
(def text
 "I;am;a;line;
  This;is;another;one
  Followed;by;this;")

(def tmp-file-name "/tmp/lines.txt")

(dotest
  (spit tmp-file-name text) ; write it to a tmp file
  (let [lines       (str/split-lines (slurp tmp-file-name))
        result      (for [line lines]
                      (for [word (str/split line #";")]
                        (str/trim word)))
        result-flat (flatten result)]
(is= result
  [["I" "am" "a" "line"]
   ["This" "is" "another" "one"]
   ["Followed" "by" "this"]])

关于样式的最后一个注释,对于Cujjor函数,你想坚持“代码>阅读文件应该是代码>读取文件< /COD> < /P> < P> >我不确定你是否需要在学校,但是既然加里已经给出了一个很好的答案,考虑这是一个额外的奖励。 您可以使用转换器对文本行进行优雅的转换。您需要的成分是,允许您将这些行视为可还原的集合,并在您完成还原时关闭读者:

(defn lines-reducible [^BufferedReader rdr]
  (reify clojure.lang.IReduceInit
    (reduce [this f init]
      (try
        (loop [state init]
          (if (reduced? state)
            @state
            (if-let [line (.readLine rdr)]
              (recur (f state line))
              state)))
        (finally
          (.close rdr))))))
现在,只要输入
work.txt
,您就可以执行以下操作:

I;am;a;string
Next;line;please
计算每个“拆分”的长度

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

(into []
      (comp
       (mapcat #(str/split % #";"))
       (map count))
      (lines-reducible (io/reader "/tmp/work.txt")))
;;=> [1 2 1 6 4 4 6]
(transduce
 (comp
  (mapcat #(str/split % #";"))
  (map count))
 +
 (lines-reducible (io/reader "/tmp/work.txt")))
;;=> 24
对所有“拆分”的长度求和。

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

(into []
      (comp
       (mapcat #(str/split % #";"))
       (map count))
      (lines-reducible (io/reader "/tmp/work.txt")))
;;=> [1 2 1 6 4 4 6]
(transduce
 (comp
  (mapcat #(str/split % #";"))
  (map count))
 +
 (lines-reducible (io/reader "/tmp/work.txt")))
;;=> 24
将所有单词的长度相加,直到找到一个长度超过5的单词

(transduce
 (comp
  (mapcat #(str/split % #";"))
  (map count))
 (fn
   ([] 0)
   ([sum] sum)
   ([sum l]
    (if (> l 5)
      (reduced sum)
      (+ sum l))))
 (lines-reducible (io/reader "/tmp/work.txt")))
或与
同时使用

(transduce
 (comp
  (mapcat #(str/split % #";"))
  (map count)
  (take-while #(> 5 %)))
 +
 (lines-reducible (io/reader "/tmp/work.txt")))

请阅读以了解更多详细信息。

我会保持它的简单性,并将其编码如下:

(-> "C:/birds.txt"
     slurp
     (clojure.string/replace #"\d" "") 
     clojure.string/split-lines)
(ns tst.demo.core
  (:use tupelo.test)
  (:require [tupelo.core :as t]
            [clojure.string :as str] ))
(def text
 "I;am;a;line;
  This;is;another;one
  Followed;by;this;")

(def tmp-file-name "/tmp/lines.txt")

(dotest
  (spit tmp-file-name text) ; write it to a tmp file
  (let [lines       (str/split-lines (slurp tmp-file-name))
        result      (for [line lines]
                      (for [word (str/split line #";")]
                        (str/trim word)))
        result-flat (flatten result)]
(is= result
  [["I" "am" "a" "line"]
   ["This" "is" "another" "one"]
   ["Followed" "by" "this"]])
请注意,
result
是一个单词的双嵌套(2D)矩阵。撤消此操作的最简单方法是使用
展平
函数生成
结果展平

(is= result-flat
  ["I" "am" "a" "line" "This" "is" "another" "one" "Followed" "by" "this"])))
您还可以使用
apply concat
,如下所示:

(is= (apply concat result) result-flat)
如果您想避免首先构建2D矩阵,可以通过
lazy gen
yield
使用
生成器函数(一种la Python):

在这种情况下,
lazy gen
创建生成器函数。
请注意,for
已替换为
doseq
,并且
yield
函数将每个单词放入输出延迟序列。

打印行,但不打印分割结果。使用
(doto(split…)。谢谢!再加上cfrick所说的,这是因为您的分割结果被丢弃了,因为行是不可变的。您需要将结果传递给println。查看我的答案了解更多详细信息生成器在某些方面可能很方便,但我认为在这种情况下,我会坚持使用
mapcat
来避免嵌套序列。当我只使用
line seq
而不是
line reducable
时,有什么区别?也许提前终止?好问题。使用
line seq
时,您将创建中间聚合,并因此进行更多的垃圾收集。此外,您还必须自己关闭读卡器(通常使用打开的
来完成)。这是为什么?我认为
transduce
将确保不创建中间集合。通过使用
line-seq
而不是
line-reduceable
,我的意思是使用(几乎)与您所写的完全相同的表达式:
(transduce(comp…(line-seq…
现在我明白了您的意思。(transduce(comp…+(line-seq(io/reader)/tmp/work.txt))也可以工作,但需要考虑两件事:1)您必须自己关闭读卡器2)line seq仍将创建一个中间延迟序列。如果lines Reduceable,则不会创建此序列。