Clojure读取CSV并将列拆分为几个向量

时间:2016-02-03 09:57:31

标签: csv vector clojure split

目前我的功能如下:

(def csv-file (.getFile  (clojure.java.io/resource "datasources.csv")))

(defn process-csv [file]
  (with-open [in-file (io/reader file)]
    (doall (csv/read-csv in-file))))

我现在需要做的是根据csv中的/ group by列生成向量,即我的process-csv输出如下所示:

(["atom" "neutron" "photon"] 
[10 22 3] 
[23 23 67])

我的目标是从列原子,中子和放大器生成3个向量。光子:

atom: [10 23]
neutron: [22 23]
photon: [3 67]

仅供参考,我在读取csv文件之前定义了3个空向量:

(def atom [])
(def neutron[])
(def photon[])

2 个答案:

答案 0 :(得分:6)

首先你不能修改这些向量,你已经定义了。这是不可变数据结构的本质。如果您确实需要可变向量,请使用user> (def items (rest '(["atom" "neutron" "photon"] [10 22 3] [23 23 67] [1 2 3] [5 6 7]))) user> (let [[atom neutron photon] (apply map vector items)] {:atom atom :neutron neutron :photon photon}) {:atom [10 23 1 5], :neutron [22 23 2 6], :photon [3 67 3 7]}

你可以这样解决你的任务:

(apply map vector items)

它是如何工作的: (map vector [10 22 3] [23 23 67] [1 2 3] [5 6 7])等于以下内容:

user> (def items '(["atom" "neutron" "photon"] [10 22 3] [23 23 67] [1 2 3] [5 6 7])) #'user/items user> (zipmap (map keyword (first items)) (apply map vector (rest items))) {:atom [10 23 1 5], :neutron [22 23 2 6], :photon [3 67 3 7]}

它会获取每个coll的第一项并制作它们的矢量,然后是第二项,依此类推。

另外,通过从csv数据头中精确获取行列名,可以使其更加健壮:

grep -l

答案 1 :(得分:1)

我将说明您可以使用的其他一些方法,这些方法可以与leetwinski说明的方法结合使用。像leetwinski一样,我建议使用哈希映射作为最终结构,而不是使用包含向量的三个符号。这取决于你。

如果您愿意,可以使用core.matrix的transpose来执行leetwinski对(apply map vector ...)所做的事情:

(require '[clojure.core.matrix :as mx])
(mx/transpose '(["atom" "neutron" "photon"] [10 22 3] [23 23 67]))

产生:

[["atom" 10 23] ["neutron" 22 23] ["photon" 3 67]]

transpose旨在用于实现core.matrix协议的任何类型的矩阵,并且正常的Clojure序列序列被core.matrix视为矩阵。

要生成地图,这里有一种方法:

(into {} (map #(vector (keyword (first %)) (rest %))
              (mx/transpose '(["atom" "neutron" "photon"] [10 22 3] [23 23 67]))))

产生:

{:atom (10 23), :neutron (22 23), :photon (3 67)}

keyword将字符串变为关键字。 #(vector ...)成对,(into {} ...)获取对的序列并从中生成哈希映射。

或者,如果您想要变量在vars中,如您所指定的那样,那么您可以使用leetwinski的let方法的变体。我建议不要def使用符号atom,因为这是Clojure中标准函数的名称。

(let [[adam neutron proton] (mx/transpose 
                              (rest '(["atom" "neutron" "photon"]
                                      [10 22 3]
                                      [23 23 67])))]
  (def adam adam)
  (def neutron neutron)
  (def proton proton))

def中使用let并不是一个好方法,但你可以做到。另外,我不建议将let定义的局部变量命名为与顶级变量相同的名称。如您所见,如果使def混乱。我故意这样做是为了展示范围规则的工作原理:在(def adam adam)中,“adam”的第一个实例代表定义的顶级变量,而“adam”的第二个实例代表本地由let定义的var,包含[10 23]。结果是:

  adam ;=> [10 23]
  neutron ;=> [22 23]
  proton ;=> [3 67]

(我认为可能有一些细微之处,我表达的错误。如果是这样,有人无疑会对此发表评论。)