繁体   English   中英

如何解析和使用Clojure中的表?

[英]How do I parse and use a table in Clojure?

我已经开始使用Clojure了,并为我为自己设置的第一个问题感到困惑。 我有一个文本文件,基本上是一个表nXm行/列。 第一行是列名,第一列是行名。 我希望能够使用clojure和稍后的查询表[row] [column]来解析此表并获取该值。

  a  b  c
1 7  8  9
2 s  q  r
3 2  7  1

那么,我如何在clojure中使用上表呢? 我不确定从哪里开始。 有人能让我朝着正确的方向前进吗?

@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"

使用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文件转换成一个矩阵,该矩阵更易于查询。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM