TL;DR: how to construct an :(a,b,c) expression from [:a,:b,:c] for use
in a macro.

Long version: I am trying to construct a macro that zips columns of
dataframes and then iterates & collects over them, eg something that
expands

@in_dataframe(df, a+b+c, 1 => a, 2 => b, 3 => c)

to

[a+b+c for (a,b,c) in zip(df[1],df[2],df[3])]

Note how indexes are values, not inferred from walking the expression,
as in DataFramesMeta. However, I want

@in_dataframe(df, a+b+c, a, b, c)

to work when column names correspond to symbols, hence the two
parse_colspec methods below.

I came up with

macro in_dataframe(df, expression, colspecs...)
    function parse_colspec(e::Expr)
        @assert e.head == :(=>)
        varname = e.args[2]
        @assert isa(varname, Symbol)
        (varname,e.args[1])
    end
    function parse_colspec(varname::Symbol)
        (varname,QuoteNode(varname))
    end
    dfvar = gensym("df")
    vars = map(parse_colspec, colspecs)
    quote
        let $dfvar = $df
            [$expression
             for $(tuple(Symbol[v[1] for v in vars]...)) in
             zip($([:($dfvar[$(v[2])]) for v in vars]...))]
        end
    end
end

Trying

macroexpand(:(@in_dataframe(df1, a+b+c, 1 => a, 2 => b, 3 => c)))

looks OK, except for the (:a,:b,:c) after the "for". I can't figure out
how to get (a,b,c). Other hints to improve style would also be
appreciated.

Regards,

Tamas

Reply via email to