【问题标题】:Check if KeyValuePair exists with LINQ's FirstOrDefault使用 LINQ 的 FirstOrDefault 检查 KeyValuePair 是否存在
【发布时间】:2009-04-27 14:57:14
【问题描述】:

我有一本字典类型

Dictionary<Guid,int>

我想使用

返回满足条件的第一个实例
var available = m_AvailableDict.FirstOrDefault(p => p.Value == 0)

但是,我如何检查我是否真的取回了 KeyValuePair?如果没有编译器错误,我似乎无法使用 != 或 == 来检查 default(KeyValuePair) 。有一个类似的线程here 似乎没有解决方案。实际上,我可以通过获取密钥并检查 Guid 的默认值来解决我的特定问题,但我很好奇是否有使用 keyvaluepair 的好方法。谢谢

【问题讨论】:

标签: c# linq null


【解决方案1】:

如果您只关心存在,您可以使用ContainsValue(0)Any(p =&gt; p.Value == 0) 代替吗?对于Dictionary&lt;,&gt;,按 搜索是不常见的;如果你是按键搜索,你可以使用TryGetValue

另一种方法:

var record = data.Where(p => p.Value == 1)
     .Select(p => new { Key = p.Key, Value = p.Value })
     .FirstOrDefault();

这会返回一个 class - 如果没有找到,则会返回 null

【讨论】:

  • 这是使用匿名类型伪装成结构的巧妙技巧。我必须记住这一点。
  • 不,我不是这个意思。元组更简单,因此认为匿名类型“试图看起来像元组”是没有意义的。我的评论背后的想法是,如果你使用var,你可以用匿名类型替换一个结构,而不需要任何引用修复,就像你上面所做的那样。
  • 匿名类方法很好,特别是如果您想对找到的结果值做任何事情。省去了两次输入谓词的麻烦(一次检查.Any,第二次抓取.First)。这是完美的,正是我解决类似问题所需要的。
  • 请注意,您可以省略匿名类型属性名称,因为如果省略它们将自动使用分配的属性名称(在这种情况下是相同的)p =&gt; new { p.Key, p.Value }
【解决方案2】:

我建议你这样改:

var query = m_AvailableDict.Where(p => p.Value == 0).Take(1).ToList();

然后您可以查看列表是否为空,如果不是,则取第一个值,例如

if (query.Count == 0)
{
    // Take action accordingly
}
else
{
    Guid key = query[0].Key;
    // Use the key
}

请注意,字典中没有“第一个”条目的真正概念 - 它的迭代顺序没有明确定义。如果您想获取 首先 使用该值输入的键/值对,则需要某种顺序保留字典。

(这是假设您确实想知道密钥 - 如果您只是在检查存在性之后,Marc's solution 是最合适的。)

【讨论】:

    【解决方案3】:

    使用 default() 关键字。

    bool exists = !available.Equals(default(KeyValuePair<Guid, int>));
    

    【讨论】:

    • 我认为结果应该倒过来,如:bool exists = !available.Equals(default(KeyValuePair));
    【解决方案4】:

    您想要的是一个Any 方法,它也为您提供匹配元素。您可以自己轻松编写此方法。

    public static class IEnumerableExtensions
    {
      public static bool TryGetFirst<TSource>(this IEnumerable<TSource> source,
                                              Func<TSource, bool> predicate,
                                              out TSource first)
      {
        foreach (TSource item in source)
        {
          if (predicate(item))
          {
            first = item;
            return true;
          }
        }
    
        first = default(TSource);
        return false;
      }
    }
    

    【讨论】:

    • 我想我可能会称之为 TryGetFirst 或 TryFirst,因为它与 TryGetValue/TryParse 相似。
    • TryGetFirst 很不错。但最终你可以随意命名它。
    • (但扩展方法的好主意 - +1 :)
    【解决方案5】:

    你可以检查一下

    available.Key==Guid.Empty
    

    【讨论】:

      【解决方案6】:

      在不指定类型的情况下检查结构(例如 KeyValuePair)的默认值的一种方法是使用 Activator 创建一个新实例:

      if (available.Equals(Activator.CreateInstance(available.GetType())))
      {
          Console.WriteLine("Not Found!");
      }
      

      【讨论】:

      • 我认为这可能类似于 Florian 使用 default() 关键字的答案。您的方法在运行时可能会比较慢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多