Closed varun-naharia closed 6 years ago
Expression doesn't support variadic functions right now, but I suppose it could in theory.
If you want a variadic min/max, you could add it yourself using a custom evaluator function, e.g.
func customExpression(_ string: String) -> Expression {
return Expression(string) { symbol, args in
switch symbol {
case .function("min", arity: _):
if args.count < 2 { return nil }
var lowest = args[0]
for arg in args where arg < lowest {
lowest = arg
}
return lowest
case .function("max", arity: _):
if args.count < 2 { return nil }
var highest = args[0]
for arg in args where arg > highest {
highest = arg
}
return highest
default:
return nil
}
}
}
let expression = customExpression("min(1, 3, 5)")
let result = try! expression.evaluate() // 1
But I want that min/max function works as it working right now but with n number of argument, as now I am unable to fully understand the code you have written in expression.swift I can't add that functionality myself. Please help me to understand it, Another functionality that I want in this expression library is dynamic variable support like
1+5+num+min(5,8,6,3)
Where num is a variable with value 10 or something else, and it's changing dynamically on run time, and I have to solve the expression with updated value each time. So expression always look on screen as it is above but when we solve the expression it will put value from variable num to expression and solve it and it will better If variable can be highlighted
The code I’ve given you implements the feature you asked for. You just have to use customExpression() instead of Expression() in your project.
Expression also supports variables of the type you describe, but without seeing your project I don’t know what you would need to implement that in your code.
Thanks for reply let me create demo may that will explain what I want to implement
Please check this url https://github.com/varun-naharia/ExpressionDemo for demo app
I want to solve the expression written in textview, Please let me know what changes I have to do.
Will you please help me I am waiting for your reply?
@varun-naharia apologies, I’m away with my family for Christmas without access to a computer. I can’t quite work out what your example does from viewing the source code on my phone. I will take a look in a few days.
Thanks, I'll be waiting for your reply, Merry Christmas to you and your family. Enjoy
@varun-naharia OK, I've run the sample, but I'm still unclear on how it is supposed to work. The "Add variable" button appends a new variable to the expression, selected from a list - but how would the value of those variables get set?
@varun-naharia anyway, regardless of the answer to that, I think this is what you need. Replace the textViewDidChange
method with the following:
func customExpression(_ string: String) -> Expression {
return Expression(string) { symbol, args in
switch symbol {
case .function("min", arity: _):
if args.count < 2 { return nil }
var lowest = args[0]
for arg in args where arg < lowest {
lowest = arg
}
return lowest
case .function("max", arity: _):
if args.count < 2 { return nil }
var highest = args[0]
for arg in args where arg > highest {
highest = arg
}
return highest
case .variable("num1"):
return Double(self.num1)
case .variable("num2"):
return Double(self.num2)
default:
return nil
}
}
}
func textViewDidChange(_ textView: UITextView) {
if let text = inputField.text, text != "" {
do {
let result = try customExpression(text).evaluate()
addOutput(String(format: "= %g", result), color: .black)
} catch {
addOutput("\(error)", color: .red)
}
}
}
Hopefully it should be obvious how you can add additional variables.
Your code is working as expected but one thing that is missing is I want add variable at run time, there is another lib on github named DDMathParser. If I use DDMathParser lib and replace the code
func textViewDidChange(_ textView: UITextView) {
if let text = inputField.text, text != "" {
do {
let result = try inputField.text!.evaluate(using: .default, Substitutions(dictionaryLiteral: ("num1", num1),("num2", num2)))
addOutput(String(format: "= %g", result), color: .black)
} catch {
addOutput("\(error)", color: .red)
}
}
}
then it's replacing string with variable, Can it be done with your lib ? but by passing Dictionary ([String:Any]) because this dictionary can created easily at run time.
@varun-naharia yes, Expression can do this, but your example code didn’t include a dictionary of variables. The reason I asked for a sample was so I could provide a solution tailored to your use case.
Here is a version that works with a dictionary of [String: Double]
called “variables”:
var variables: [String: Double] // your variables
func customExpression(_ string: String) -> Expression {
return Expression(string) { symbol, args in
switch symbol {
case .function("min", arity: _):
if args.count < 2 { return nil }
var lowest = args[0]
for arg in args where arg < lowest {
lowest = arg
}
return lowest
case .function("max", arity: _):
if args.count < 2 { return nil }
var highest = args[0]
for arg in args where arg > highest {
highest = arg
}
return highest
case let .variable(name):
return self.variables[name]
default:
return nil
}
}
}
Thanks problem solved. But it'll be better if you make the code for function more understandable so anyone can add new function to lib.
@varun-naharia The reason this is so complex is your requirement of having a variadic min/max function. If it weren’t for that, the code would be much simpler (no need for customExpression
):
let result = try Expression(text, constants: variables).evaluate()
I’ll consider if there is an easier way to support variadic functions, but flexibility is always at odds with simplicity, and I’ve tried to optimize for making the common use cases simple.
@varun-naharia good news: If you update to Expression 0.10.0, it now has built-in variadic min/max functions, so you can remove the customExpression()
function and just use:
let result = try Expression(text, constants: variables).evaluate()
Why there is no n number of argument for min/max function ?