当我将对象列表作为值时,我想找到相应的键。 假设我有一个词典,
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);
我在寻找类似的解决方案。
答案 0 :(得分:3)
LINQ的性能不是很高,但使用LINQ编写正确可读的代码通常更容易。如果没有重复值,我会使用HashSet<T>
而不是列表。如果你知道它是什么类型我会使用该类型而不是对象。
您的代码的LINQ版本将是....
List.Contains
:
List<string> keysWithValue = dict
.Where(kv => kv.Value.Contains(foo))
.Select(kv => kv.Key);
.ToList();
或Enumerable.Any
:
List<string> keysWithValue = dict
.Where(kv => kv.Value.Any(v => foo.Equals(v)))
.Select(kv => kv.Key);
.ToList();
但如上所述,这不会更有效率。提高性能的一种方法是使用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();
请注意,如果没有列表包含该值,这甚至可以工作,那么结果将是一个空列表。