当值是C#中的对象列表时,如何找到字典的键?

时间:2016-08-26 14:52:05

标签: c# linq dictionary

当我将对象列表作为值时,我想找到相应的键。 假设我有一个词典,

 Dictionary<string, List<object>> dict = new Dictionary<string, List<object>>(); 

我知道我可以做点什么,

foreach (var item in dict)
{
    foreach (var subItem in item.Value)
    {
        if (subItem.Equals(foo))
        {
              Console.WriteLine(item.Key);
        }
     }
}

但这需要花费大量时间才能拥有庞大的数据集。有更快的解决方案吗?

我知道使用LINQ找到给定值的键的正常方法是:

var keysWithMatchingValues = dict.Where(p => p.Value == myObject).Select(p => p.Key);

我在寻找类似的解决方案。

1 个答案:

答案 0 :(得分:3)

LINQ的性能不是很高,但使用LINQ编写正确可读的代码通常更容易。如果没有重复值,我会使用HashSet<T>而不是列表。如果你知道它是什么类型我会使用该类型而不是对象。

您的代码的LINQ版本将是....

  1. List.Contains

    List<string> keysWithValue =  dict
        .Where(kv => kv.Value.Contains(foo))
        .Select(kv => kv.Key);
        .ToList();
    
  2. Enumerable.Any

    List<string> keysWithValue =  dict
        .Where(kv => kv.Value.Any(v => foo.Equals(v)))
        .Select(kv => kv.Key);
        .ToList();
    
  3. 但如上所述,这不会更有效率。提高性能的一种方法是使用Lookup<TKey, TValue>。如果字典没有改变,你只需要创建一次:

    var valueToKeyLookup = dict  // make it an instance field, so that you don't have to create it always
        .SelectMany(kv => kv.Value
            .Distinct()
            .Select(v => new {Key = kv.Key, Value = v})
        )
        .ToLookup(x => x.Value, x => x.Key);
    

    现在剩下的代码非常简洁高效:

    List<string> allKeysWithFoo = valueToKeyLookup[foo].ToList();
    

    请注意,如果没有列表包含该值,这甚至可以工作,那么结果将是一个空列表。