我已经开始使用clojure的旅程,并为我为自己设置的第一个问题感到困惑。我有一个文本文件,基本上是一个表nXm行/列。第一行是列名,第一列是行名。我希望能够使用clojure和后来的查询表[row] [column]解析此表并获取该值。
a b c
1 7 8 9
2 s q r
3 2 7 1
那么,我将如何在clojure中使用上表?我不确定从哪里开始。有人能让我朝着正确的方向前进吗?
答案 0 :(得分:5)
@Hendekagon的答案是完成工作的好方法,但我们可以看一下从头开始实施。虽然可能不是最好的解决方案,但希望样本设计能帮助您实现目标。
如果你想查询你的结构,在Clojure中,你将会考虑地图。让我们把目标看作是我们的目标:
{"1" {"a" "7", "b" "8", "c" "9"},
"2" {"a" "s", "b" "q", "c" "r"},
"3" {"a" "2", "b" "7", "c" "1"}}
这里,行名是列名到表元素的映射的关键。使用此结构,我们可以使用get-in
轻松查询表的元素。
(get-in table ["2" "b"]) ; => "q"
好。我们怎么做?
让我们假装我们已经在我们的文件中读取并将其作为字符串。然后,我们需要将其转换为我们的地图图。我们的功能看起来像这样:
(defn parse-table
[raw-table-data]
...)
第一步是提取所有重要的数据位 - 行名,列名和表元素。但是,在我们抓住它们之前,我们需要将raw-table-data
字符串解析为更容易遍历的结构。我们将字符串拆分为换行符,然后使用辅助函数tokens
对空格上的行进行标记。
(use '[clojure.string :only [split split-lines trim]])
(defn tokens
[s]
(-> s trim (split #"\s+")))
(defn parse-table
[raw-table-data]
(let [table-data (map tokens (split-lines raw-table-data))]
...
)
table-data
看起来像这样:
[["a", "b", "c"],
["1", "7", "8", "9"],
["2", "s", "q", "r"],
["3", "2", "7", "1"]]
这使得很容易找到好东西:
(defn parse-table
[raw-table-data]
(let [table-data (map tokens (split-lines raw-table-data))
column-names (first table-data)
row-names (map first (next table-data))
contents (map next (next table-data))]
...
)
随着数据的消失,我们只需将它们拼接在一起。一种简单的方法是构建我们所有的行到列到元素的单独映射,然后将它们组合起来。我会提到这不是最有效的方法,但它非常干净。
创建一个辅助函数pairs
,它只是并排地粘贴两个集合的元素,我们可以使用for
理解来获得一系列映射。
(defn pairs
[coll1 coll2]
(map vector coll1 coll2))
(for [[row-name row-contents] (pairs row-names contents)
[column-name element] (pairs column-names row-contents)]
{row-name {column-name element}})
这给出了一系列地图到地图。我们只需要将它合并到一个大地图中,功能就完成了。
(defn parse-table
[raw-table-data]
(let [table-data (map tokens (split-lines raw-table-data))
column-names (first table-data)
row-names (map first (next table-data))
contents (map next (next table-data))]
(apply merge-with merge
(for [[row-name row-contents] (pairs row-names contents)
[column-name element] (pairs column-names row-contents)]
{row-name {column-name element}}))))
现在,我们可以搞砸一个表文件并解析它。
(def table
(->
"file"
slurp
parse-table))
这让我们达到了目标。
(println (get-in table ["2" "b"])) ; => "q"
答案 1 :(得分:2)
使用https://github.com/clojure/data.csv,您的文件将成为一系列向量,每个向量都是一行,然后您可以使用如下函数解析行:
(defn parse-row [[a b c]]
[(Integer/parseInt a) (Double/parseDouble b) (str c)])
(注意参数列表中的解构,这使得读取列名更容易)
然后(map parse-row rows)
获取解析后的表
但是,另一种方法是使用Incanter,它会将您的csv文件转换为更易于查询的矩阵。