【问题标题】:LINQ querying nested dictionary with multiple key value selection in C#LINQ在C#中使用多个键值选择查询嵌套字典
【发布时间】:2020-06-15 19:48:46
【问题描述】:

我遇到了一个问题,找不到任何合适的解决方案。我有一个嵌套字典,其布局如下:

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 个条件来获取行的 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 中,因为它给了我以下错误:

无法将 [] 索引应用于“键值对”类型的表达式

【问题讨论】:

  • 关于您问题的第一部分(使用 2 或 3 个标准):这是一个合乎逻辑的问题吗?您正在请求info.Key == "marks1" &amp;&amp; info.Key == "marks2",但您可能想要info.Key == "marks1" || info.Key == "marks2"(注意逻辑或
  • 是的,你是对的,我只是在这里作为一个例子

标签: c# linq dictionary key-value


【解决方案1】:

我试过了,效果很好

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

【讨论】:

  • Thankyou 工作正常..知道我们如何以 linq 的查询格式做到这一点
  • @TalhaKazi 它不起作用,因为info.Key 不能同时是marks1Marks2。正如我在回答中提到的那样,您也可以使用查询语法来做到这一点
【解决方案2】:

你可以使用

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

输出

1 
2

【讨论】:

    【解决方案3】:

    外部来自:
    dictKeyValuePairs 的序列,其中 Key 是 int,Value 是内部 Dictionary&lt;string, dynamic&gt;。因此,id 是这个 KeyValuePair 序列中的一个元素:它就是这样一个 KeyValuePair。

    Inner from:
    id.Value 是一个Dictionary&lt;string, dynamic&gt;,它是一个 KeyValuepairs 的字符串,其中每个 Key 都是一个字符串,每个 Value 都是一个动态的。

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

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

    如果我读到这篇文章,您只需要内部字典中的那些 KeyValuePair,其字符串 Key 等于“marks1”以及等于“marks2”。你确定你想要那个吗?在我看来,结果将是一个空集合。

    唉,你没有写你的要求,所以我不得不猜测。

    我认为,从外部字典中的每个 KeyValuePair 元素中,您都需要 Key(这是外部字典中的 int),以及内部字典中所有 KeyValuePair 的序列

    • 要么(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 中,创建一个新对象,其中包含两个属性:KeyValues

    Key 属性是您的 KeyValuepair 中的 Key。

    Values 属性是一个列表。它包含由内部字典制成的对象,这些对象属于外部字典中 Key 的值。

    这个内部字典也是一个 KeyValuePairs 的序列。我只保留其中的一些内部 KeyValuePairs,即只保留那些:

    • Key 等于 "marks1" AND Convert.ToDouble(value) 大于 10
    • 或:键等于“marks2 AND Convert.ToDouble(value) 大于 20

    从内部字典中剩余的每个 KeyValuePair 中,我创建了一个包含属性 NameValue 的新对象。

    Name 是内部 KeyValuePair 的 Key(等于 "marks1" 或 "marks2") Value 是这个内部 KeyValuePair 的 Value。

    当然如果你想要其他属性,你可以选择它们而不是我选择的那些:

    .Select(innerKeyValuePair => new
    {
        Marks = innerKeyValuePair.Key,                     // equals "marks1" OR "marks2"
        Value = Convert.ToDouble(innerKeyValuePair.Value),
    })
    .ToList(),
    

    【讨论】:

    • 哇,非常感谢您的全面解释。我实际上已经以字典形式转换了一个数据表,其中每个 id 代表一条记录,内部字典包含作为键的列和作为值的数据,因此每个 id 都是我试图查询的记录
    【解决方案4】:

    你可以像这样扁平化字典:

        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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多