LINQ запрашивает вложенный словарь с выбором нескольких значений ключа в C# - PullRequest
4 голосов
/ 03 марта 2020

Я столкнулся с проблемой и не могу найти подходящего решения для нее. У меня есть вложенный словарь, который имеет макет, подобный следующему:

var dict = new Dictionary<int, Dictionary<string , dynamic>>()
{
 0 : {Name : "abc" , marks1 : 05 , Marks2 : 10 , marks3 : 39},
 1 : {Name : "efg" , marks1 : 20 , Marks2 : 30 , marks3 : 25},
 2 : {Name : "hig" , marks1 : 30 , Marks2 : 40 , marks3 : 33},
 3 : {Name : "xyz" , marks1 : 40 , Marks2 : 10 , marks3 : 50}
}

Я пытаюсь выполнить запрос с помощью LINQ, чтобы получить id этих запросов, которые true, но я не могу выбрать два или три критерия для запроса. Для одного значения ключа запрос ниже работает нормально :

    var query = from id in dict
                    from info in id.Value
                    where (info.Key == "marks1" && Convert.ToDouble(info.Value) > 10)
                    select id

Но когда я пытаюсь использовать 2 или 3 критерия для получения идентификатора строки, например, ниже его не работает .

    var query = from id in dict
                    from info in id.Value
                    where (info.Key == "marks1" && Convert.ToDouble(info.Value) > 10) 
                    && (info.Key == "marks2" && Convert.ToDouble(info.Value) > 20)
                    select id 

Кроме того, если мне нужно сравнить значения друг с другом, например, значения marks1 должны быть больше mark2 и mark3. Как я могу выполнить такой запрос? Особенно, когда мне не разрешают получать доступ к значению по ключу, как это:

info["marks1"] > ( info["mark2"] && info["marks3"] )

в LINQ, поскольку это дает мне следующую ошибку:

не может применить индексирование с [] к выражение типа 'keyvaluepair

Ответы [ 4 ]

2 голосов
/ 03 марта 2020

Вы можете использовать

var result= dict.Where(x=>Convert.ToDouble(x.Value["marks1"])>10 
                       && Convert.ToDouble(x.Value["Marks2"])>20)
                .Select(x=>x.Key);

Выход

1 
2
2 голосов
/ 03 марта 2020

Я попробовал это, и это сработало

var result = dict.Where(x => x.Value.Any(y => y.Key == "marks1" && int.Parse(y.Value) > 10))
                 .Where(x => x.Value.Any(y => y.Key == "marks2" && int.Parse(y.Value) > 31));
1 голос
/ 03 марта 2020

Вы можете выровнять словарь так:

    dict.Select(item=> new { 
                            Id = item.Key, 
                            Name = item.Value["Name"],
                            marks1 = Convert.ToDouble(item.Value["marks1"]), 
                            marks2 = Convert.ToDouble(item.Value["marks2"]),
                            marks3 = Convert.ToDouble(item.Value["marks3"]) 
                          }
                 )
           .Where(item=> item.marks1 > 10 && 
                         item.marks2 > 20)
           .Select(item=> item.Id)

Этот запрос возвращает идентификатор записи. Если вам нужны полные записи выбранных данных, вы можете использовать это:

    dict.Select(item=> new { 
                            item = item, 
                            Name = item.Value["Name"],
                            marks1 = Convert.ToDouble(item.Value["marks1"]), 
                            marks2 = Convert.ToDouble(item.Value["marks2"]),
                            marks3 = Convert.ToDouble(item.Value["marks3"]) 
                          }
                 )
           .Where(item=> item.marks1 > 10 && 
                         item.marks2 > 20)
           .Select(item=> item)
1 голос
/ 03 марта 2020

Наружный от:
dict - это последовательность KeyValuePairs, где ключом является int, а значением является внутреннее Dictionary<string, dynamic>. Следовательно, id - это один элемент из этой последовательности KeyValuePairs: это один из таких KeyValuePair.

Внутренний из:
id.Value - это Dictionary<string, dynamic>, который представляет собой строку KeyValuepairs, где каждый Ключ - это строка, и каждое значение равно Dynami c.

. Вы не хотите, чтобы все KeyValuePairs из внутреннего словаря, вам нужны только некоторые из них:

where (info.Key == "marks1" && Convert.ToDouble(info.Value) > 10) 
   && (info.Key == "marks2" && Convert.ToDouble(info.Value) > 20)

Если я прочитайте это, вы хотите, чтобы только те KeyValuePairs из внутреннего словаря со строкой Key, равной "marks1", а также равным "marks2". Вы уверены, что хотите этого? Мне кажется, что результатом будет пустая коллекция.

Увы, вы не написали свои требования, поэтому я должен догадаться.

Я думаю, что из каждого элемента KeyValuePair из вашего внешнего словаря вы хотите получить ключ (который является int из вашего внешнего словаря), а также все последовательности всех KeyValuePairs из внутреннего словаря, которые имеют либо

  • (Key == "marks1) «AND Convert.ToDouble (info.Value)> 10)
  • ИЛИ (Key ==« marks2 »И AND Convert.ToDouble (info.Value)> 20)

I ' Я не очень знаком с синтаксисом запроса, поэтому вместо него я буду использовать methodSyntax.

Dictionary<int, Dictionary<string, dynamic>> dict = ...;
var result = dict.Select( outerKeyValuePair => new
{
    Key = outerKeyValuePair.Key,
    Values = outerKeyValuePair.Value
        // I don't want all values from the inner dictionary
        // I only want those where (Key == "marks1" and ...) OR (Key == "marks2 and ...)
        .Where(innerKeyValuePair => 
              (innerKeyValuePair.Key == "marks1" && Convert.ToDouble(innerKeyValuePair.Value) > 10)
              ||
              (innerKeyValuePair.Key == "marks2" && Convert.ToDouble(innerKeyValuePair.Value) > 20))

         // from the remaining inner KeyValuePairs select the properties that you want
         .Select(innerKeyValuePair => new
         {
              Name = innerKeyValuePair.Key,
              Value = innerKeyValuePair.Value,
         })
         .ToList(),
    });

Словом: ваш внешний словарь - это последовательность внешних KeyValuePairs. Из каждого keyValuePair в этой последовательности создайте один новый объект, содержащий два свойства: Key и Values.

Свойство Key является ключом от вашей KeyValuepair.

The Values свойства это список. Он содержит объекты, сделанные из внутреннего словаря, который принадлежит значению Key из внешнего словаря.

Этот внутренний словарь также является последовательностью KeyValuePairs. Я сохраняю только некоторые из этих внутренних KeyValuePairs, а именно только те, в которых:

  • Ключ равен "marks1" И И Convert.ToDouble (значение) больше, чем 10
  • ИЛИ: Ключ равен "marks2" И Convert.ToDouble (значение) больше 20

Из каждого оставшегося KeyValuePair из внутреннего словаря я создаю один новый объект, содержащий свойства Name и Value.

Name - это ключ внутренней KeyValuePair (которая равна «marks1» или «marks2») Value - это значение этой внутренней KeyValuePair.

Конечно, если вы хотите другие свойства, вы можете выбрать их вместо тех, что я выбрал:

.Select(innerKeyValuePair => new
{
    Marks = innerKeyValuePair.Key,                     // equals "marks1" OR "marks2"
    Value = Convert.ToDouble(innerKeyValuePair.Value),
})
.ToList(),
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...