#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 вызывает ошибку сборки