| Signature | Description | Parameters |
|---|---|---|
template<typename F, typename ... Ts> DataFrame & pipe(F &&func, Ts ... args) requires std::invocable<F, DataFrame &, Ts ...> && std::same_as<std::invoke_result_t<F, DataFrame &, Ts ...>, DataFrame &>; |
This function allows users to chain a series of transformative functions into a functional programming notation. The function series may or may not have side effects. This is more than just a syntactic sugar. This allows the user to write structured, modular, and easy to read and understand code. It also enables users to create data processing pipelines that can start with a single DataFrame as it evolves with or without side effects while moving through the pipeline. |
Ts: The list of types of args func: A function that will operate on the DataFrame with or without side effects. The singanure of the F function must be: DataFrame &func(DataFrame &, args ...);
args: The list of arguments to be passed to func function |
static DTDataFrame &read_df(DTDataFrame &df) { try { df.read("DT_IBM.csv", io_format::csv2); } catch (const DataFrameError &ex) { std::cout << ex.what() << std::endl; ::exit(-1); } return (df); } // ------------------------------------- static DTDataFrame &multiply_col(DTDataFrame &df, const std::string &col_name, double factor) { df.apply<double>(col_name.c_str(), [factor](const DateTime &, double &val) -> bool { val *= factor; return (true); }); return (df); } // ------------------------------------- static DTDataFrame &add_col(DTDataFrame &dt_df, const StrDataFrame2 &str_df) { const auto &volume = str_df.get_column<long>("IBM_Volume"); dt_df.load_column("IBM_Volume 2", volume); return (dt_df); } // ------------------------------------- static auto verify = [](DTDataFrame &df) -> DTDataFrame & { const auto &volume1 = df.get_column<long>("IBM_Volume"); const auto &volume2 = df.get_column<long>("IBM_Volume 2"); const auto &open = df.get_column<double>("IBM_Open"); assert(volume1.size() == 5031); assert(volume1.size() == volume2.size()); assert(volume1[500] == volume2[500]); assert(open.size() == 5031); assert((std::fabs(open[5003] - 241.6) < 0.01)); return (df); }; // ------------------------------------- struct PrintDF { PrintDF(long row_count) : row_count_(row_count) { } DTDataFrame &operator()(DTDataFrame &df) { df.write<std::ostream, double, long>(std::cout, io_format::pretty_prt, { .precision = 2, .max_recs = row_count_ }); return(df); } private: const long row_count_; }; // ------------------------------------- static void test_pipe() { std::cout << "\nTesting pipe( ) ..." << std::endl; StrDataFrame2 str_df; try { str_df.read("IBM.csv", io_format::csv2); } catch (const DataFrameError &ex) { std::cout << ex.what() << std::endl; ::exit(-1); } DTDataFrame dt_df; PrintDF printer(5L); dt_df.pipe(read_df) .pipe(multiply_col, "IBM_Open", 2.0) .pipe(add_col, str_df) .pipe(verify) .pipe(std::bind(&PrintDF::operator(), printer, std::placeholders::_1)); }