0

I am using following model to Deserialize a JSON response from api endpoint

    public class APIModel
    { 
        public int Prop1 { get; set; }
        public int Prop2 { get; set; }
        public int Prop3 { get; set; }          
         
        public Dictionary<string, Dictionary<string, string>> DictMaster { get; set; }                      
    }
    

The JSON from API is like

            [{
            -----------------
            "DictMaster": {
                "0": {
                    "0": "No",
                    "1": "94041"
                },
                "1": {
                    "0": "Date",
                    "1": "08 / 06 / 2020"
                },
                "2": {
                    "0": "sDate",
                    "1": "15 / 06 / 2020"
                },
                "3": {
                    "0": "ONo",
                    "1": "113003"
                }
            }
        },
        { 
            -----------------
            "DictMaster": {
                "0": {
                    "0": " Net",
                    "1": "£ 212.40"
                },
                "1": {
                    "0": "Car",
                    "1": "£ 0.00"
                },
                "2": {
                    "0": "Amount",
                    "1": "£ 42.48"
                },
                "3": {
                    "0": " Total",
                    "1": "£ 254.88"
                }
            }
        },
        {
             -----------------
            "DictMaster": {
                "0": {
                    "0": "Qty col",
                    "1": "Ref col",
                    "2": "Description",
                    "3": "Unit",
                    "4": "Net"
                },
                "1": {
                    "0": "2",
                    "1": "4d05",
                    "2": " Ball -G -   Red",
                    "3": "8.85",
                    "4": "2140"
                }
            }
        }
    ]

This is the code for deserialization and working correctly

var models = JsonConvert.DeserializeObject<List<APIModel>>(json);
    
List<Dictionary<string, string>> 
    tablemodel = (from p in  models
                  from d in p.DictMaster
                  select d.Value).ToList();
    

The list contains 10 items and is working well and this is basically the list of all dictionary<string, string> items available in the JSON response. I would like to apply one more filtering condition to this list. I have a set of search keywords and need to compare the dictionary values with the search keywords. If any of the dictionary value contains a portion of search keyword, then I have to select that specific "DictMaster" and convert the values from them to a List<Dictionary<string,string>>.

In this given JSON, the dictionary under the last of "DictMaster" contains some values from the search keyword list "Qty" & "Ref" So its required to pick the last instance of "DictMaster" as result set

string[] search_keys = new string[] {"Qty" ,"ref" };
List<Dictionary<string, string>> tablemodel = (from p in models
                                               from v in p.DictMaster
                                               where search_keys.Any(v.Value.ContainsValue)
                                               select v.Value).ToList();
                                                           

But this is returning 0 items. I am expecting this to return 2 items

How can I select or filter dictionary with at least one match for the list of search keywords?

Based on the suggestions in answer sections and comments, I managed to ended up on a query like below to get the result

string[] search_keys = new string[] {"qty" ,"ref" };

var responseModel = (from p in models
                     from dict in p.DictMaster
                     from x in p.DictMaster.Values
                     from val in dict.Value
                     where search_keys.Any(d => val.Value.ToLower().Contains(d))
                     select x.Values).ToList();
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Sebastian
  • 4,625
  • 17
  • 76
  • 145

2 Answers2

1

Well this works, but you need the search values in lower case too. And currently you have to distinct it as well.

        var search_keys = new string[] { "qty", "ref" };
        var tablemodel = new List<Dictionary<string, string>>();

        foreach (var dict in models.SelectMany(model => model.DictMaster))
        {
            tablemodel.AddRange(from val in dict.Value where search_keys.Any(d => val.Value.ToLower().Contains(d)) select dict.Value);
        }

You could use a hashset to distinct them, but depends a bit of the size of your JSON I guess:

        string[] search_keys = new string[] { "qty", "ref" };
        var tablemodel = new HashSet<Dictionary<string, string>>();

        foreach (var dict in
            from model in models
            from dict in model.DictMaster
            from val in dict.Value
            where search_keys.Any(d => val.Value.ToLower().Contains(d))
            select dict)
        {
            tablemodel.Add(dict.Value);
        }
Yeronimo
  • 1,731
  • 15
  • 28
  • This is correctly filtering the DIctionary with a match . But not adding the other DIctionary items in that level to the list. As per example there will be 2 set of Dictionary exists under the last "DictMaster" item with a match on keywords – Sebastian Jun 10 '21 at 14:59
  • 1
    Managed to get a query to return expected result and your answer helped most to reach there. I edited the question now – Sebastian Jun 11 '21 at 08:20
-2

Consider your LINQ query:

from p in models
    from v in p.DictMaster
    where search_keys.All(v.Value.ContainsValue)
    select v.Value

Based on your model, v.Value will be something like:

 "3": {
          "0": " Total",
          "1": "£ 254.88"
      }

This will never match your search string. You need another level in your LINQ query:

from p in models
    from v in p.DictMaster
        from x in v.Value
        where search_keys.Any(x.Value.ContainsValue)
        select x.Value
RobJarvis
  • 360
  • 3
  • 8