AlexR
AlexR

Reputation: 5644

DDMathParser: How to define default values for variables

I am using DDMathParser to parse formulas and calculate the results, which works great.

Question:

Is it possible to set variables to default values in case they do not exist in the substitution dictionary?

Example:

My formula $a + $b requires two variables $a and $b. However, my substitution dictionary contains only an value for variable key a (e.g. 1), but does not contain an key b.

What would be the preferred way to define variable b to be 0 as default value and avoid the parsing error message "unable to resolve variable"?

Thank you!

Edit

The way I am using DDMathParser is by looping over multiple formulas and providing the same variable substitution dictionary to each formula. Sometimes, I don't have values for the variables: In this case the variables (keys and values) would not be included in the dictionary.

Depending on the formula itself, I would like to return nil as result for the formula if one of the variables does not exist (e.g. I don't have a value for profit and the formula is $profit / $revenue, I would like to return nil which I can convert to a NSString of n/a later) or set the variable to 0 if it is does not exist in the dictionary (e.g. for a formula like $profitA + $profitB + $profitC, I would like to assume 0 for any missing variables ($profitA, $profitB or $profitC).

For this reason, I cannot use a generic solution, which always returns 0 or nil, but would need to put this logic in the formula (e.g. as a custom function).

Upvotes: 2

Views: 306

Answers (2)

Dave DeLong
Dave DeLong

Reputation: 243156

DDMathParser author here.

Is it possible to set variables to default values in case they do not exist in the substitution dictionary?

Kind of. You could do it by supplying a variableResolver block to the math evaluator:

DDMathEvaluator *evaluator = [DDMathEvaluator sharedMathEvaluator];
[evaluator setVariableResolver:^(NSString *variable) { return @0; }];
NSNumber *n = [evaluator evaluateString:myString withSubstitutions:mySubstitutions];

The variable resolver block gets executed whenever the evaluator comes across a variable that it can't find in the substitutions dictionary.

Would it be feasible to add a custom function to DDMathParser like defaultZero($b) which retrieves the variable b if it exists or zero if not?

Hm, clever idea. You could, but you would essentially by mimicking the behavior of the variableResolver block. You'd create a new DDMathFunction block and use the -[DDMathEvaluator registerFunction:forName:] to tell the evaluator about it.

However, I'd recommend just supplying a variable resolver block. It'd be much simpler.


Here's how you'd define a defaultZero function that returns either the value of the argument or 0 (if the argument can't be evaluated):

DMathEvaluator *evaluator = [DDMathEvaluator sharedMathEvaluator];
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError *__autoreleasing *error) {
    NSNumber *argValue = nil;
    if ([args count] == 1) {
        // defaultZero() only supports a single argument
        // for anything else, return 0
        DDExpression *arg = [args objectAtIndex:0];
        NSError *argError = nil;
        argValue = [eval evaluateExpression:arg withSubstitutions:vars error:&argError];
    }

    if (argValue == nil) {
        // return 0 if either the arg can't be eval'd or there isn't 1 arg
        argValue = @0;
    }
    return [DDExpression numberExpressionWithNumber:argValue];

} forName:@"defaultZero"];

Upvotes: 2

rmaddy
rmaddy

Reputation: 318924

Initialize the substitution dictionary with appropriate default values first, then update it with any actual values.

Upvotes: 3

Related Questions