Значение словаря содержит любой из элементов строкового массива

#c# #linq #dictionary #json-deserialization

Вопрос:

Я использую следующую модель для десериализации ответа JSON от конечной точки api

     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; }                      
    }
    
 

JSON из API выглядит так

             [{
            -----------------
            "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"
                }
            }
        }
    ]
 

Это код для десериализации и правильной работы

 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();
    
 

Список содержит 10 элементов и работает хорошо, и это в основном список всех элементов словаря<строка, строка>, доступных в ответе JSON. Я хотел бы применить к этому списку еще одно условие фильтрации. У меня есть набор ключевых слов для поиска, и мне нужно сравнить значения словаря с ключевыми словами поиска. Если какое-либо значение словаря содержит часть ключевого слова поиска, то я должен выбрать этот конкретный «ДиктМастер» и преобразовать значения из них в a List<Dictionary<string,string>> .

В данном JSON словарь под последним из «DictMaster» содержит некоторые значения из списка ключевых слов поиска «Кол-во» и «Ссылка», поэтому требуется выбрать последний экземпляр «DictMaster» в качестве результирующего набора

 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();
                                                           
 

Но это возвращает 0 элементов. Я ожидаю, что это вернет 2 предмета

Как я могу выбрать или отфильтровать словарь, по крайней мере, с одним совпадением для списка ключевых слов поиска?

Основываясь на предложениях в разделах ответов и комментариях, мне удалось выполнить запрос, подобный приведенному ниже, чтобы получить результат

 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();
 

Комментарии:

1. Разве Все не должны быть Какими-То?

2. @Yeronimo Нет разницы в выводе. Сначала я попробовал с любым, а затем со всеми и 1 элементом в массиве ключевых слов

3. Похоже, вам нужно провести сравнение без учета регистра

4. @juharr я пробовал с тем же случаем , но все равно 0 результатов

5. Это работает, если вы ищете весь термин. Так, например, «Кол-во кол.». Таким образом, ваше содержание соответствует только целому слову. Нам нужно частичное совпадение

Ответ №1:

Что ж, это работает, но вам также нужны значения поиска в нижнем регистре. И в настоящее время вы также должны различать его.

         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);
        }
 

Вы могли бы использовать набор хэшей, чтобы различать их, но, я думаю, это немного зависит от размера вашего JSON:

         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);
        }
 

Комментарии:

1. Это правильная фильтрация словаря<строка,строка> с совпадением . Но не добавляйте в список другие элементы словаря<строка,строка> на этом уровне. Согласно примеру,в последнем элементе «ДиктМастер» будет 2 набора словаря<строка, строка> с совпадением по ключевым словам

2. Удалось получить запрос, возвращающий ожидаемый результат, и ваш ответ больше всего помог туда добраться. Теперь я отредактировал вопрос

Ответ №2:

Рассмотрите свой запрос LINQ:

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

Основываясь на вашей модели, v.Value будет что-то вроде:

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

Это никогда не будет соответствовать вашей строке поиска. Вам нужен другой уровень в вашем запросе LINQ:

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

Комментарии:

1. x.Значение. Значение containsValue вызывает ошибку сборки