我有一系列序列,从clojure-csv输出。
(def s1 [[:000-00-0000 "SMITH" "JOHN" 27][:000-00-0001 "FARMER" "FANNY" 28]])
我有一个列号[0 3]的向量,我想用它来从每个序列中提取数据。
我没有编写一个函数来将可变数量的地图形式压缩在一起,而是认为宏可能会成功。但是,我遇到了麻烦。
此宏接受序列和列“mask”
(defmacro map-cols [seq & columns]
(for [col# columns
:let [mc# `(map #(nth % ~col# nil) ~seq)]]
mc#))
(map-cols s1 cols)
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IFn bene-csv.core/eval2168
我希望生成出现的多个地图表单 以下内容:
(zipmap (map #(nth % 0 nil) s1) (map #(nth % 1 nil) s1))
{:000-00-0001 "FARMER", :000-00-0000 "SMITH"}
我很欣赏我做错的一些想法。当然,我可以根据需要提取的列数来定制函数。
谢谢。
编辑:
修改后的宏
(defmacro map-cols [seq & columns]
(vec (for [col columns
:let [mc `(map #(nth % ~col nil) ~seq)]]
mc)))
(apply zipmap (map-cols s1 cols))
ArityException Wrong number of args (1) passed to: core$zipmap clojure.lang.AFn.throwArity
答案 0 :(得分:4)
您正在混合将在宏扩展时执行的代码与宏将输出的代码。在输入语法引用之前,您不需要使用auto-gensym(在您的示例中为col#,mc#)。至于宏输出,它必须始终只生成一个表单。您似乎期望它生成多个表单(每个表单一个),但这不是如何工作的。您的宏输出目前看起来像
((map #(nth % 0 nil) s1) (map #(nth % 1 nil) s1))
这是一个有两名成员的表格。头部位置的成员应该是一个函数,整个表单应该被评估为函数调用。
挽救此问题的方法是使用for
将vec
包裹在宏中,然后使用(apply zipmap (map-cols s1 cols))
。
这回答你的直接问题,但解决方案仍然没有意义:zipmap
只需要两个args,而不是你想要的可变数量的args,输出是一个地图,而不是一个序列将你的领域拉到一起。使用(map vector seq1 seq2 ...)
实现压缩。