Back

switch_case

Overview

The switch_case function applies different transformations to elements in a Serie based on multiple conditions. It evaluates a series of conditions for each element and applies the first matching transformation. If no condition matches, a default transformation is applied. This provides a powerful way to implement multi-branched conditional logic similar to a switch statement in imperative programming.

Function Signatures


          // Main function
          template <typename T, typename R>
          Serie<R> switch_case(
              const Serie<T> &serie,
              const std::vector<std::pair<std::function<bool(const T &)>,
                                      std::function<R(const T &)>>> &cases,
              std::function<R(const T &)> default_case);
          
          // Bound version for pipeline operations
          template <typename T, typename R>
          auto bind_switch_case(
              const std::vector<std::pair<std::function<bool(const T &)>,
                                      std::function<R(const T &)>>> &cases,
              std::function<R(const T &)> default_case);
        

Parameters

Parameter Type Description
serie const Serie<T>& The input Serie to apply conditional transformations to.
cases std::vector<std::pair<condition, transform>> A vector of condition-transformation pairs. Each pair consists of:
  • A condition function that takes an element and returns a boolean
  • A transformation function that takes an element and returns a transformed value
The pairs are evaluated in order, and the first matching condition's transformation is applied.
default_case std::function<R(const T &)> Default transformation to apply when no condition matches.

Return Value

A new Serie where each element has been transformed according to the first matching condition, or by the default transformation if no condition matches. The type of elements in the returned Serie (type R) may be different from the input Serie's element type.

Example Usage

Basic Example: Grading System

// Create a Serie of test scores
df::Serie<double> scores{95.0, 82.5, 67.0, 45.5, 78.0, 91.5, 59.0};

// Convert scores to letter grades
auto letter_grades = df::switch_case<double, std::string>(scores,
    {
        {[](double score) { return score >= 90.0; }, [](double) { return "A"; }},
        {[](double score) { return score >= 80.0; }, [](double) { return "B"; }},
        {[](double score) { return score >= 70.0; }, [](double) { return "C"; }},
        {[](double score) { return score >= 60.0; }, [](double) { return "D"; }}
    },
    [](double) { return "F"; }  // default case
);
// letter_grades = {"A", "B", "C", "F", "C", "A", "F"}
Complex Example: Data Categorization

// Define a data point structure
struct DataPoint {
    double value;
    std::string category;
    bool is_valid;
};

// Create a Serie of data points
df::Serie<DataPoint> data_points{
    {1.2, "temperature", true},
    {-5.0, "temperature", false},
    {75.3, "humidity", true},
    {101.2, "pressure", true},
    {0.0, "pressure", false},
    {42.8, "humidity", true}
};

// Process data points based on multiple criteria
auto processed = df::switch_case<DataPoint, std::string>(data_points,
    {
        // Invalid data
        {[](const DataPoint& d) { return !d.is_valid; }, 
         [](const DataPoint& d) { return "Invalid " + d.category + " reading"; }},
        
        // Temperature criteria
        {[](const DataPoint& d) { return d.category == "temperature" && d.value > 30.0; }, 
         [](const DataPoint&) { return "High temperature"; }},
        
        {[](const DataPoint& d) { return d.category == "temperature"; }, 
         [](const DataPoint&) { return "Normal temperature"; }},
        
        // Humidity criteria
        {[](const DataPoint& d) { return d.category == "humidity" && d.value > 70.0; }, 
         [](const DataPoint&) { return "High humidity"; }},
        
        {[](const DataPoint& d) { return d.category == "humidity"; }, 
         [](const DataPoint&) { return "Normal humidity"; }}
    },
    [](const DataPoint& d) { return "Other reading: " + d.category; }  // default case
);
// processed = {"Normal temperature", "Invalid temperature reading", "High humidity", 
//              "Other reading: pressure", "Invalid pressure reading", "Normal humidity"}
Numerical Processing Example

// Create a Serie of numbers
df::Serie<double> values{-5.2, 0.0, 3.7, -2.1, 10.5, 0.01, -8.3, 25.0};

// Apply different mathematical transformations based on value ranges
auto transformed = df::switch_case<double, double>(values,
    {
        // For large positive values (> 10), take the square root
        {[](double x) { return x > 10.0; }, 
         [](double x) { return std::sqrt(x); }},
        
        // For small positive values (0 < x <= 10), square the value
        {[](double x) { return x > 0.0 && x <= 10.0; }, 
         [](double x) { return x * x; }},
        
        // For zero values, return 0
        {[](double x) { return x == 0.0; }, 
         [](double) { return 0.0; }}
    },
    // For negative values, take the absolute value and negate
    [](double x) { return -std::abs(x); }
);
// transformed = {-5.2, 0.0, 13.69, -2.1, 3.24, 0.0001, -8.3, 5.0}
Pipeline Example

// Create a Serie of integers
df::Serie<int> numbers{-10, -5, 0, 3, 7, 12, 15, 20};

// Use bind_switch_case in a pipeline
auto result = numbers
    | df::bind_map([](int x, size_t) { return x * 2; })  // Double all values
    | df::bind_switch_case<int, std::string>(
        {
            {[](int x) { return x < 0; }, 
             [](int x) { return "Negative: " + std::to_string(x); }},
             
            {[](int x) { return x == 0; }, 
             [](int) { return "Zero"; }},
             
            {[](int x) { return x > 0 && x < 20; }, 
             [](int x) { return "Small Positive: " + std::to_string(x); }},
             
            {[](int x) { return x >= 20 && x < 30; }, 
             [](int x) { return "Medium Positive: " + std::to_string(x); }}
        },
        [](int x) { return "Large Positive: " + std::to_string(x); }
    );
// result = {"Negative: -20", "Negative: -10", "Zero", "Small Positive: 6", 
//           "Small Positive: 14", "Small Positive: 24", "Medium Positive: 30", "Large Positive: 40"}

Implementation Notes

  • The switch_case function creates a new Serie without modifying the original Serie.
  • The conditions are evaluated in order, and only the first matching condition's transformation is applied.
  • If no condition matches, the default transformation is applied.
  • All transformations (including the default case) must return the same type (R).
  • The return type R can be different from the input Serie's element type T.
  • The switch_case function is more flexible than if_then_else for handling multiple conditions.
  • For performance reasons, avoid defining complex lambda functions inside the switch_case call for large Series.

Related Functions