2

clojure-csv から出力された一連のシーケンスがあります。

(def s1 [[:000-00-0000 "SMITH" "JOHN" 27][:000-00-0001 "FARMER" "FANNY" 28]])

各シーケンスからデータを抽出するために使用したい列番号 [0 3] のベクトルがあります。

可変数のマップ フォームを 1 つにまとめる関数を作成するのではなく、マクロを使用するとうまくいくのではないかと考えました。しかし、私は問題を抱えています。

このマクロは、シーケンスと列「マスク」を受け入れます

   (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"}

私が間違っていることについていくつかのアイデアをいただければ幸いです。もちろん、抽出する必要がある列の数に合わせて a 関数を調整することもできます。

ありがとうございました。

編集:

変更されたマクロ

(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
4

1 に答える 1

4

マクロ展開時に実行されるコードと、マクロが出力するコードを混同しています。syntax-quote を入力するまでは、auto-gensym (例では col#、mc#) を使用する必要はありません。マクロ出力に関しては、常に正確に 1 つのフォームを生成する必要があります。複数のフォーム (列ごとに 1 つ) を生成することを期待しているようですが、これは機能しません。マクロ出力は現在次のようになります

((map #(nth % 0 nil) s1) (map #(nth % 1 nil) s1))

これは2人のメンバーを持つフォームです。先頭位置のメンバは関数であることが期待され、フォーム全体が関数呼び出しとして評価されることになっています。

これを救済する方法forは、マクロを a でラップしてvecから を使用すること(apply zipmap (map-cols s1 cols))です。

それはあなたの当面の質問に答えますが、解決策はまだ意味がありませzipmapん.あなたが言ったように可変数ではなく、正確に2つの引数が必要であり、出力はマップであり、フィールドをまとめたシーケンスではありません. 圧縮は を使用して実現され(map vector seq1 seq2 ...)ます。

于 2012-04-17T13:46:19.783 に答える