Back
pipe
Overview
The pipe function enables functional composition by allowing multiple operations to be chained together into a single processing pipeline. It provides a clean, readable way to express complex transformations on Series.
Function Signatures
// Base case: end of pipe chain
template <typename T>
auto pipe(T&& value);
// General case: pipe with operation
template <typename T, typename F, typename... Rest>
auto pipe(T&& value, F&& operation, Rest&&... rest);
// Operator | overload for pipe operations
template <typename T, typename F>
auto operator|(T&& value, F&& operation);
// make_pipe factory function
template <typename... F>
auto make_pipe(F&&... operations);
Parameters
| Parameter | Type | Description |
|---|---|---|
| value | T&& (any type) | The input value to be processed through the pipeline. |
| operation | F&& (callable) | A function or operation to apply to the value. Should accept the input value and return a transformed value. |
| rest | Rest&&... (callables) | Additional operations to be applied in sequence. |
Return Value
The result of applying all operations in sequence to the input value.
Example Usage
Basic Pipe Example
// Create a Serie
df::Serie<int> numbers{1, 2, 3, 4, 5};
// Using pipe function with multiple operations
auto result = df::pipe(
numbers,
[](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x * 2; }); },
[](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x + 10; }); }
); // {12, 14, 16, 18, 20}
// Using the | operator (more readable)
auto piped_result = numbers
| [](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x * 2; }); }
| [](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x + 10; }); };
// {12, 14, 16, 18, 20}
Using Bind Functions
// Create a Serie
df::Serie<double> values{1.1, 2.2, 3.3, 4.4, 5.5};
// Using bind functions with the pipe operator
auto result = values
| df::bind_map([](double x, size_t) { return x * 2; }) // Double each value
| df::bind_map([](double x, size_t) { return std::round(x); }) // Round to nearest integer
| df::bind_map([](double x, size_t) { return x > 8; }); // Convert to boolean
// {false, false, true, true, true}
// Create a custom bind function
auto double_values = [](const df::Serie<double>& s) {
return s.map([](double x, size_t) { return x * 2; });
};
// Use it in a pipe
auto doubled = values | double_values; // {2.2, 4.4, 6.6, 8.8, 11.0}
Creating Reusable Pipelines
// Create a reusable pipeline using make_pipe
auto process_values = df::make_pipe(
df::bind_map([](double x, size_t) { return x * 2; }), // Double
df::bind_map([](double x, size_t) { return x + 10; }), // Add 10
df::bind_map([](double x, size_t) { return std::round(x); }) // Round
);
// Apply the pipeline to different Series
df::Serie<double> values1{1.1, 2.2, 3.3};
df::Serie<double> values2{4.4, 5.5, 6.6};
auto result1 = process_values(values1); // {12, 14, 17}
auto result2 = process_values(values2); // {19, 21, 23}
// Combine multiple operations
auto preprocess = df::bind_map([](double x, size_t) { return std::abs(x); });
auto calculate = df::bind_map([](double x, size_t) { return std::sqrt(x); });
auto format = df::bind_map([](double x, size_t) { return std::round(x * 100) / 100; });
// Create a pipeline with all operations
auto analyze = df::make_pipe(preprocess, calculate, format);
// Apply the combined pipeline
df::Serie<double> input{-16.0, 25.0, -4.0, 9.0};
auto output = analyze(input); // {4.0, 5.0, 2.0, 3.0}
Complex Transformation Pipeline
// Process student data
df::Serie<std::string> names{"Alice Smith", "Bob Johnson", "Charlie Brown"};
df::Serie<double> scores{87.5, 92.0, 78.5};
// Create a pipeline to generate formatted reports
auto report_pipeline = df::make_pipe(
// Combine name and score into a tuple
[](const df::Serie<std::string>& names, const df::Serie<double>& scores) {
return df::zip(names, scores);
},
// Format each student record
df::bind_map([](const auto& tuple, size_t index) {
auto [name, score] = tuple;
std::string grade;
if (score >= 90) grade = "A";
else if (score >= 80) grade = "B";
else if (score >= 70) grade = "C";
else grade = "D";
return "Student #" + std::to_string(index + 1) + ": " + name +
" - Score: " + std::to_string(score) +
" - Grade: " + grade;
})
);
// Apply the pipeline
auto reports = report_pipeline(names, scores);
// {"Student #1: Alice Smith - Score: 87.5 - Grade: B",
// "Student #2: Bob Johnson - Score: 92.0 - Grade: A",
// "Student #3: Charlie Brown - Score: 78.5 - Grade: C"}
Implementation Notes
- The pipe function and | operator both execute operations from left to right.
- Each operation must accept the result of the previous operation as its input.
- The make_pipe function creates a reusable pipeline that can be applied to different inputs.
- Bind functions (e.g., bind_map, bind_forEach) are designed to work seamlessly with pipe.
- Pipe operations are evaluated lazily, meaning they are only executed when needed.