在C#中查询多键值嵌套字典的LINQ方法

4

我面临一个问题,找不到合适的解决方案。我有一个嵌套字典,它的结构如下:

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查询来获取那些查询的idtrue的结果,但我无法选择两个或三个查询条件。对于一个键值对,下面的查询可以很好地工作
    var query = from id in dict
                    from info in id.Value
                    where (info.Key == "marks1" && Convert.ToDouble(info.Value) > 10)
                    select id

但是,当我尝试使用2或3个条件来获取以下行的ID时,它无法正常工作。

    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的值应大于mark2mark3的值。我该如何执行这样的查询?特别是当我不允许像这样通过键来访问值时:

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

在LINQ中,当我使用以下代码时会出现以下错误:

不能将索引[]应用于类型为'keyvaluepair < string, dynamic>的表达式


关于您问题的第一部分(使用2或3个条件):这是一个逻辑问题吗?您正在请求 info.Key == "marks1" && info.Key == "marks2",但您可能想要 info.Key == "marks1" || info.Key == "marks2"(请注意逻辑或)。 - mu88
是的,你说得对,我只是在这里举了一个例子。 - Talha Kazi
4个回答

2
我尝试了这个方法,它起作用了。
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));

谢谢,很好用。有没有想法如何在LINQ的查询格式中实现这个? - Talha Kazi
@TalhaKazi 这不起作用是因为info.Key不能同时是marks1Marks2。您也可以使用查询语法,就像我在答案中提到的那样。 - Pavel Anikhouski

2
您可以使用:
var result= dict.Where(x=>Convert.ToDouble(x.Value["marks1"])>10 
                       && Convert.ToDouble(x.Value["Marks2"])>20)
                .Select(x=>x.Key);

输出

1 
2

1

来自外部:
dict 是一个 KeyValuePairs 序列,其中 Key 是一个 int,Value 是内部的 Dictionary<string, dynamic>。因此,id 是这个 KeyValuePairs 序列中的一个元素:它是这样一个 KeyValuePair。

来自内部:
id.Value 是一个 Dictionary<string, dynamic>,它是一个 KeyValuepairs 的字符串,其中每个 Key 是一个字符串,每个 Value 是一个动态值。

你不想要内部字典中的所有 KeyValuePairs,你只想要其中的一些:

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

如果我理解正确,您只想从内部字典中具有字符串键等于“marks1”并且等于“marks2”的那些KeyValuePairs。您确定要这样吗?在我看来,结果将是一个空集合。
遗憾的是,您没有写下您的要求,所以我必须猜测。
我认为您想要从外部字典的每个KeyValuePair元素中获取Key(即外部字典中的int),以及来自内部字典的所有KeyValuePairs序列,这些KeyValuePairs具有以下特征:
-either (Key == "marks1" AND Convert.ToDouble(info.Value) > 10) -OR (Key == "marks2" AND Convert.ToDouble(info.Value) > 20)
我不是很熟悉查询语法,因此我将使用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中,创建一个新对象,包含两个属性:KeyValuesKey属性是KeyValuepair中的键。 Values属性是一个列表。它包含由属于外部字典中Key值的内部字典创建的对象。
这个内部字典也是一个KeyValuePairs序列。我只保留其中的一些内部KeyValuePairs,即仅满足以下条件的KeyValuePairs:
  • Key等于“marks1”且Convert.ToDouble(value)大于10
  • 或:Key等于“marks2”,并且Convert.ToDouble(value)大于20
从内部字典中剩下的每个KeyValuePair中,我创建一个新对象,包含NameValue属性。 Name是内部KeyValuePair的键(它等于“marks1”或“marks2”)。 Value是此内部KeyValuePair的值。
当然,如果您想要其他属性,可以选择我选择的属性。
.Select(innerKeyValuePair => new
{
    Marks = innerKeyValuePair.Key,                     // equals "marks1" OR "marks2"
    Value = Convert.ToDouble(innerKeyValuePair.Value),
})
.ToList(),

哇,非常感谢那个详细的解释。我已经将一个数据表转换成了字典形式,其中每个id代表一条记录,内部字典包含列作为键和数据作为值,因此每个id都是一条记录,我正在尝试查询它们。 - Talha Kazi

1
你可以像这样压缩字典:

    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)

这个查询返回记录的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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接