简体   繁体   中英

Filter key value pairs with dynamic operators

I have a series of resource objects whose properties are defined as key values. Also jobs to choose from among these resources are defined as follows.

    class Resource
    {
        public string Name { get; set; }
        public Dictionary<string, string> Properties { get; set; }
    }
    
    
    class Job
    {
        public string Name { get; set; }
        public List<KeyValueOperator> Properties { get; set; }
    }
    
    class KeyValueOperator
    {
        public string Key { get; set; }
        public string Value { get; set; }
        public EnumOperator Operator { get; set; }
    }
    
    enum EnumOperator
    {
        Equals = 0,
        LessThan = 1,
        LessThanEqual = 2,
        GreaterThan = 3,
        GreaterThanEqual = 4
    }

void Main()
{
    System.Collections.Generic.List<Resource> resources = new List<UserQuery.Resource>();
    var res1 = new Resource { Name = "Res1", Properties = new Dictionary<string, string>() };
    res1.Properties.Add("color", "red");
    res1.Properties.Add("size", "small");
    res1.Properties.Add("age", "3");
    res1.Properties.Add("speed", "10");
    resources.Add(res1);

    var res2 = new Resource { Name = "Res2", Properties = new Dictionary<string, string>() };
    res2.Properties.Add("color", "blue");
    res2.Properties.Add("size", "small");
    res2.Properties.Add("age", "4");
    res2.Properties.Add("speed", "8");
    resources.Add(res2);

    var res3 = new Resource { Name = "Res3", Properties = new Dictionary<string, string>() };
    res3.Properties.Add("color", "red");
    res3.Properties.Add("size", "large");
    res3.Properties.Add("age", "10");
    res3.Properties.Add("speed", "5");
    resources.Add(res2);
    
    
    System.Collections.Generic.List<KeyValueOperator> jobProps = new List<UserQuery.KeyValueOperator>();
    
    jobProps.Add(new KeyValueOperator { Key = "color", Value = "red", Operator = EnumOperator.Equals });
    jobProps.Add(new KeyValueOperator { Key = "size", Value = "small", Operator = EnumOperator.Equals });
    jobProps.Add(new KeyValueOperator { Key = "age", Value = "2", Operator = EnumOperator.LessThanEqual });
    Job job1 = new Job { Name = "job1", Properties = jobProps };
}

In case of checking only equality from the key value list, the following code fragment works.

var filtered = resources
    .Where(x => job1.Properties
        .All(y => x.Properties
            .Any(r => r.Key == y.Key && r.Value == y.Value)))
    .ToList();

I want to filter not only with equality, but also with operators defined as EnumOperator. Is there a library that can do this? Or how can I do?

One simple way to accomplish this is using the CompareTo() method. You can create an extension method for EnumOperator that implements the logic for each operator:

static class EnumOperatorExtensions
{
    public static bool Execute(this EnumOperator @operator, string left, string right)
    {
        int comparison = left.CompareTo(right);
        return @operator switch
        {
            EnumOperator.Equals => comparison == 0,
            EnumOperator.LessThanEqual => comparison <= 0,
            EnumOperator.LessThan => comparison < 0,
            EnumOperator.GreaterThanEqual => comparison >= 0,
            EnumOperator.GreaterThan => comparison > 0,
            _ => throw new NotImplementedException()
        };
    }
}

And then your usage of it would look like:

List<Resource> filtered = resources
    .Where(x => job1.Properties
        .All(y => x.Properties
            .Any(r => r.Key == y.Key && y.Operator.Execute(y.Value, r.Value))))
    .ToList();

Using the setup you provided, this gives the following results:

[
  {
    "Name": "Res1",
    "Properties": {
      "color": "red",
      "size": "small",
      "age": "3",
      "speed": "10"
    }
  }
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM