use*_*010 3 file-io split clojure
我正在学校学习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)))))
Run Code Online (Sandbox Code Playgroud)
当我这样做时,我仍然得到输出:
"I;Am;A;String;"
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
Mic*_*ent 11
我不确定你是否在学校需要这个,但由于加里已经给出了一个很好的答案,所以认为这是一个奖励.
您可以使用传感器对文本行进行优雅的转换.您需要的成分是允许您将线条视为可简化的集合,并在您完成减少后关闭阅读器:
(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))))))
Run Code Online (Sandbox Code Playgroud)
现在,您可以根据输入执行以下操作work.txt
:
I;am;a;string
Next;line;please
Run Code Online (Sandbox Code Playgroud)
计算每个"分裂"的长度
(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]
Run Code Online (Sandbox Code Playgroud)
总结所有"分裂"的长度
(transduce
(comp
(mapcat #(str/split % #";"))
(map count))
+
(lines-reducible (io/reader "/tmp/work.txt")))
;;=> 24
Run Code Online (Sandbox Code Playgroud)
将所有单词的长度相加,直到找到长于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")))
Run Code Online (Sandbox Code Playgroud)
或者take-while
:
(transduce
(comp
(mapcat #(str/split % #";"))
(map count)
(take-while #(> 5 %)))
+
(lines-reducible (io/reader "/tmp/work.txt")))
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请阅读https://tech.grammarly.com/blog/building-etl-pipelines-with-clojure.
TL; DR拥抱REPL并拥抱不变性
你的问题是"我错过了什么?" 而且我会说你错过了Clojure的最佳功能之一,即REPL.
编辑:您可能也会遗漏Clojure使用不可变数据结构
考虑以下代码段:
(doseq [x [1 2 3]]
(inc x)
(prn x))
Run Code Online (Sandbox Code Playgroud)
此代码不打印"2 3 4"
它打印"1 2 3"因为x不是可变变量.
在第一次迭代中 (inc x)
调用,返回2,然后抛出它,因为它没有被传递给任何东西,然后(prn x)
打印x的值,它仍然是1.
现在考虑以下代码段:
(doseq [x [1 2 3]] (prn (inc x)))
Run Code Online (Sandbox Code Playgroud)
在第一次迭代期间,inc将其返回值传递给prn,因此得到2
很长的例子:
我不想剥夺你自己解决问题的机会所以我会用另一个问题作为例子.
给定"birds.txt"
带有数据的文件,"1chicken\n 2duck\n 3Larry"
您要编写一个函数,该函数接收一个文件并返回一系列鸟名
让我们把这个问题分解成更小的块:
首先让我们读取文件并将其拆分成行
(slurp "birds.txt")
会给我们整个文件一个字符串
clojure.string/split-lines
将为我们提供一个集合,每行作为集合中的一个元素
(clojure.string/split-lines (slurp "birds.txt"))
得到我们 ["1chicken" "2duck" "3Larry"]
此时我们可以在该集合上映射一些函数来去掉像这样的数字 (map #(clojure.string/replace % #"\d" "") birds-collection)
或者我们可以在整个文件是一个字符串时将该步骤向上移动.
现在我们已经拥有了所有的部分,我们可以将它们放在一个功能管道中,其中一个部分的结果输入到下一个部分
在Clojure中有一个很好的宏观使这个更容易读,->
宏
它接受一次计算的结果并将其作为第一个参数注入下一个计算
所以我们的管道看起来像这样:
(-> "C:/birds.txt"
slurp
(clojure.string/replace #"\d" "")
clojure.string/split-lines)
Run Code Online (Sandbox Code Playgroud)
风格上最后一个音符,为Clojure的函数,你要坚持到烤肉情况下这样readFile
应该是read-file
归档时间: |
|
查看次数: |
1764 次 |
最近记录: |