In this post, Running RDataFrame's Define In For Loop, an example of putting expressions-as-strings in a vector then define dataframes based on the expressions in a loop is provided.
I’m wondering if I can do something like this:
auto lambdas = vector<F>{[](double x) { return x; }, [](double x, double y) { return x+y; }};
auto names = vector<string>{"a", "b"};
auto params = vector<vector<string>> {{"x"}, {"x", "y"}};
initDf = RDataFrame("tree", "ntp.root");
auto applyDefine(RNode df, vector<F> lambdas, vector<string> names, vector<vector<string> params, int idx=0) {
if (i == names.size()) return df;
return applyDefines(df.Define(names[i], lambdas[i], params[i]), lambdas, names, paras, i + 1);
}
applyDefine(initDf, names, lambdas, params);
Hi @yipengsun ,
In C++ each lambda has its own different type which only the compiler knows, so you cannot create a std::vector<lambda> container. You can create a vector of std::function and then pass lambdas which will be converted into the function type
But that only works with functions of the same signature, since std::vector can only contain objects of the same type. From your example above I see already two different signatures, so that wouldn’t be possible at all.
As for the F type you see in the documentation, that’s just the typename of the template parameter, a generic callable type that you may pass to the Define operation. That includes a lambda, a function, an std::function, a class that has an operator() .
Cheers,
Vincenzo
I see. So the only way to make it work would be to declare these functions of different signatures in gInterepreter, and call them by the string (say, "func(x)"), then these Define’s will be JIT’ed at run-time, by the interpreter (even if the source code is compiled).
Hi @yipengsun ,
In C++17, with some template trickery, you can use std::tuple and fold expressions instead of a vector of lambdas and a for loop. Example coming.