codingseb / ExpressionEvaluator

A Simple Math and Pseudo C# Expression Evaluator in One C# File. Can also execute small C# like scripts
MIT License
595 stars 99 forks source link

Evaluating expressions on arrays. #166

Open mercurial-moon opened 1 week ago

mercurial-moon commented 1 week ago

Hi, Recently came across numexpr https://github.com/pydata/numexpr that can do expressions on arrays eg. 3*a+4*b where a and b are arrays.

Is this kind of expression possible in ExpressionEvaluator. if not can we get it done using linq or a lambda expression.

codingseb commented 19 hours ago

Hi @mercurial-moon,

I am not a specialist of array operations and how it should be implemented. EE do not implement it directly but it could be added with the code below as a start of a solution. (If you inherits ExpressionEvaluator you can rededefine operators)

using CodingSeb.ExpressionEvaluator;
using Newtonsoft.Json;
using System.Collections;

ExpressionEvaluator evaluator = new EE();

evaluator.Variables["a"] = new double[] { 4d, 3.4 };

string expression = "3 * a"; 
Console.WriteLine(expression);
Console.WriteLine(JsonConvert.SerializeObject(evaluator.Evaluate(expression)));
Console.WriteLine(string.Empty);

public class EE : ExpressionEvaluator
{
    private Func<dynamic, dynamic, object> mutiplyFuncBase;
    private Func<dynamic, dynamic, object> addFuncBase;
    // ...

    private object ExtendedMultiply(dynamic left, dynamic right)
    {
        if (left is IEnumerable leftEnumerable)
            return leftEnumerable.Cast<object>().Select(element => ExtendedMultiply(element, right));
        if(right is IEnumerable rightEnumerable)
            return rightEnumerable.Cast<object>().Select(element => ExtendedMultiply(left, element));

            return mutiplyFuncBase(left, right);
    }

    private object ExtendedAdd(dynamic left, dynamic right)
    {
        // Here I am not sure how to implement it
        return null;
    }

    public EE()
    {
        var multiplyDict = OperatorsEvaluations.First(dict => dict.ContainsKey(ExpressionOperator.Multiply));
        mutiplyFuncBase = multiplyDict[ExpressionOperator.Multiply];
        multiplyDict[ExpressionOperator.Multiply] = ExtendedMultiply;

        var addDict = OperatorsEvaluations.First(dict => dict.ContainsKey(ExpressionOperator.Plus));
        addFuncBase = addDict[ExpressionOperator.Plus];
        addDict[ExpressionOperator.Plus] = ExtendedAdd;
    }
}

Otherwise if you want to use the Linq Select directly in the expression you need to pass your array as an array of object.

evaluator.Variables["a"] = new object[] { 4d, 3.4 };
evaluator.Evaluate("a.Select(element => element * 3)");

Or cast it with a.Cast<object>().Select(...)

One more time I am not sure if my implementation of array multiplication is correct. And do not know how to do the addition.