【问题标题】:How to query a C# dictionary and return a specific set of values如何查询 C# 字典并返回一组特定的值
【发布时间】:2012-03-12 05:34:18
【问题描述】:

我的 C# 程序中有一个字典,其中包含一个键 + 值列表。

值为itemid, Month, Year, Count

我想通过比较一组值 (itemid, Month, Year) 来查询字典,如果存在特定的 itemid + Month + Year,则返回 true 或 false。

因此,如果所有 3 个值 (itemid + Month + Year) 都存在,则返回 true,否则返回 false。

我试过这样的

(if (myd.Select(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month  && d.Value.Year == DateRange.Year).ToString() != "")

上述方法无效。

【问题讨论】:

  • 尝试遍历字典并比较将它们添加到另一个字典的值

标签: c# linq collections lambda


【解决方案1】:

您似乎误解了 Select() 方法的用法。选择创建一个“投影”;给定一个元素的输入集合(可枚举),它产生一个输出可枚举,其基数相等,但由元素组成,每个元素都是输入对应元素的转换结果。

您需要的是 Where() 方法(它返回一个列表,其基数小于或等于输入,其中包含布尔条件为真的输入元素)或 Any() 方法(如果输入中的任何元素满足条件,则返回单个“true”或“false”):

if(myd.Where(d => d.Value.itemid == item.itemid 
                && d.Value.Month == DateRange.Month 
                && d.Value.Year == DateRange.Year).Count() >= 1)
   ...

//produces the equivalent result but generally performs faster
if(myd.Any(d => d.Value.itemid == item.itemid 
                && d.Value.Month == DateRange.Month 
                && d.Value.Year == DateRange.Year))
   ...

【讨论】:

  • where和count结合效率不高,也不好。
  • ... 我在代码的注释中说明了这一点。他是使用 Where 还是 Any 取决于他需要什么结果; Where() 的结果是一个可以进一步处理的可枚举,而 Any() 产生一个具体的结果。我给了他两个,这样他就可以看到这两种方法都采用了他尝试与 Select 一起使用的 lambda 并产生正确的答案。
  • 用法很明显,它在if条件内,而且where和count的组合也不好(除了在linq2sql中,仍然是多余的)你可以写:myList.Count(x= >f(x)),没有必要使用 where (导致一次迭代,每次检查总共 2n 而不是 n),同样正如我一开始所说,它不好(可读性,效率,逻辑上,技术上,任何东西想到了)。
  • 谢谢。我试过了,但是当我使用 myd.Any 时,我总是出错。我可以通过调试我的应用程序看到该项目确实存在于字典中。
  • 我想我已经找到了我全都假的原因。我的字典似乎在值中添加了空格。示例月 =“4”年 =“2011”
【解决方案2】:

如果像 linq-Syntax 一样,它会检查是否存在至少一个满足所有三个条件的项目:

if((from d in myd
where d.Value.itemid == item.itemid
&& d.Value.Month == DateRange.Month
&& d.Value.Year == DateRange.Year).FirstOrDefault() != null)

【讨论】:

  • 可以简单的写成:myList.FirstOrDefault(x=>f(x)),其实可以在FirstOrDefault中使用where条件函数。
【解决方案3】:

如果您想使用另一个键(在本例中为 itemid、月、年,可能放置在元组中)进行查找,则需要创建第二个字典,并且您需要在添加时维护它们/从中删除。

【讨论】:

    【解决方案4】:

    使用 Where to filter(我假设您的代码中的条件定义正确......您没有给我们足够的信息来评估它)

    var filteredDictionary = myd.Where(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month  && d.Value.Year == DateRange.Year)
    

    使用 Select 将 KeyValuePair 转换为一个值

    var filteredValues = filteredDictionary.Select(x=>x.Value)
    

    使用 Any 返回一个项目是否存在的布尔值

    bool matchExists = myd.Any(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month  && d.Value.Year == DateRange.Year)
    

    Any 对于您描述的问题将是最有效的,因为它会停止评估字典中的项目并在找到匹配项后立即返回 True

    【讨论】:

      【解决方案5】:

      如果您使用的是 .NET 4.0,则可以使用元组作为键。

      var dict = new Dictionary<Tuple<int,int,int>,MyValueType>();
      

      然后你可以测试一个值是否存在

      var key = new Tuple<int,int,int>(item.itemid, DateRange.Month, DateRange.Year);
      if(dict.ContainsKey(key)) {
         ...
      }
      

      或者你可以测试

      if(dict.ContainsValue(referenceValue)) {
          ...
      }
      

      您必须向它传递一个包含您要查找的内容的参考值。确保你的值类型实现了EqualityComparer&lt;T&gt;

      第一种方法会快得多,因为字典是通过键访问的。如果您没有通过键访问字典,您也可以使用List&lt;T&gt;

      【讨论】:

        猜你喜欢
        • 2022-01-15
        • 1970-01-01
        • 2015-03-10
        • 2021-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多