我对编程既新又老 - 主要是我在工作中编写了很多小的Perl脚本.当我想学习Lisp时,Clojure就出来了,所以我也在不知道Java的情况下学习Clojure.这很难,但到目前为止一直很有趣.
我已经看过几个类似问题的例子,但没有任何东西可以映射到我的问题空间.有没有规范的方法来提取Clojure中CSV文件的每一行的值列表?
这是一些实际工作的Perl代码; 包含非Perlers的评论:
# convert_survey_to_cartography.pl
open INFILE, "< coords.csv"; # Input format "Northing,Easting,Elevation,PointID"
open OUTFILE, "> coords.txt"; # Output format "PointID X Y Z".
while (<INFILE>) { # Read line by line; line bound to $_ as a string.
chomp $_; # Strips out each line's <CR><LF> chars.
@fields = split /,/, $_; # Extract the line's field values into a list.
$y = $fields[0]; # y = Northing
$x = $fields[1]; # x = Easting
$z = $fields[2]; # z = Elevation
$p = $fields[3]; # p = PointID
print OUTFILE "$p $x $y $z\n" # New file, changed field order, different delimiter.
}
Run Code Online (Sandbox Code Playgroud)
我在Clojure中有点困惑,并尝试以一种命令式的方式将它拼凑在一起:
; convert-survey-to-cartography.clj
(use 'clojure.contrib.duck-streams)
(let
[infile "coords.csv" outfile "coords.txt"]
(with-open [rdr (reader infile)]
(def coord (line-seq rdr))
( ...then a miracle occurs... )
(write-lines outfile ":x :y :z :p")))
Run Code Online (Sandbox Code Playgroud)
我不希望最后一行实际工作,但它得到了重点.我正在寻找以下内容:
(def values (interleave (:p :y :x :z) (re-split #"," coord)))
Run Code Online (Sandbox Code Playgroud)
比尔,谢谢
kot*_*rak 15
请不要使用嵌套的def.它没有,你认为它做什么.def始终是全球性的!对于当地人来说,请改用.虽然库函数很难知道,但这里有一个版本,通常编写函数式编程的一些特性,特别是clojure.
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coordsRun Code Online (Sandbox Code Playgroud)
可以通过(doc translate-coords)在REPL中查询文档字符串.工作例如.适用于所有核心功能.因此提供一个是个好主意.
"Reads coordinates from infile, translates them with the given
translator and writes the result to outfile."Run Code Online (Sandbox Code Playgroud)
翻译器是一个(可能是匿名的)函数,它从周围的样板中提取翻译.因此,我们可以使用不同的转换规则重用此函数.这里的类型提示避免构造函数的反射.
[translator #^String infile #^String outfile]Run Code Online (Sandbox Code Playgroud)
打开文件.with-open将保证文件在其主体离开时关闭.无论是通过正常的"从底部掉下来"还是通过抛出的异常.
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]Run Code Online (Sandbox Code Playgroud)
我们将*out*流临时绑定到输出文件.因此绑定中的任何打印都将打印到文件中.
(binding [*out* out]Run Code Online (Sandbox Code Playgroud)
该map方法:取序列和给定函数应用于每个元素并返回结果的序列.这#()是匿名函数的简写符号.它需要一个参数,填充在%.这doseq基本上是输入的循环.因为我们为副作用(即打印到文件)这样做,所以doseq是正确的构造.经验法则:maplazy => for result,doseq:eager => for side effects.
(doseq [coords (map #(.split % ",") (line-seq in))]Run Code Online (Sandbox Code Playgroud)
println照顾\n到最后一行.interpose获取seq并在其元素之间添加第一个参数(在我们的例子中为"").(apply str [1 2 3])等效于(str 1 2 3)动态构造函数调用并且很有用.这->>是一个相对较新的clojure宏,它有助于提高可读性.它表示"接受第一个参数并将其作为最后一项添加到函数调用中".给定->>的相当于:(println (apply str (interpose " " (translator coords)))).(编辑:另一个注意事项:因为分隔符是\space,我们在这里也可以这样写(apply println (translator coords)),但是interpose版本允许像我们对翻译器功能一样参数化分隔符,而短版本会硬连线\space.)
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."Run Code Online (Sandbox Code Playgroud)
这里我们使用解构(注意双[[]]).这意味着函数的参数可以转换为seq,例如.矢量或列表.将第一个元素绑定到第二个元素y,x依此类推.
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")Run Code Online (Sandbox Code Playgroud)
这里再次不那么波动:
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coords
"Reads coordinates from infile, translates them with the given
translator and writes the result to outfile."
[translator #^String infile #^String outfile]
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]
(binding [*out* out]
(doseq [coords (map #(.split % ",") (line-seq in))]
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.
编辑:对于CSV阅读,您可能需要类似OpenCSV的内容.
这是一种方式:
(use '(clojure.contrib duck-streams str-utils)) ;;'
(with-out-writer "coords.txt"
(doseq [line (read-lines "coords.csv")]
(let [[x y z p] (re-split #"," line)]
(println (str-join \space [p x y z])))))
Run Code Online (Sandbox Code Playgroud)
with-out-writer绑定*out*使得您打印的所有内容都将转到您指定的文件名或流,而不是标准输出.
使用def它并不是惯用的.更好的方法是使用let.我正在使用解构来将每行的4个字段分配给4行let名称; 那么你可以用那些做你想做的事.
如果你为了副作用(例如I/O)而迭代某些东西,你通常应该去doseq.如果你想将每一行收集到一个哈希映射中并稍后用它们做一些事情,你可以使用for:
(with-out-writer "coords.txt"
(for [line (read-lines "coords.csv")]
(let [fields (re-split #"," line)]
(zipmap [:x :y :z :p] fields))))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2581 次 |
| 最近记录: |