如果我有一个字典的枚举
IEnumerable<IDictionary<string, float>> enumeration
我可以对它执行Linq查询,以便我可以使用相同的键从枚举中的每个字典中选择一个值吗?
我可以循环执行此操作:
float f;
foreach (var dictionary in enumeration)
{
if (dictionary.TryGetValue("some key", out f))
{
Console.WriteLine(f);
}
}
(最终的计划是将查询的性能与等效的嵌套循环语句进行比较(枚举本身由另一个查询或一组等效的循环组成)。)
答案 0 :(得分:5)
你在寻找这样的东西:
IEnumerable<float> vals = enumeration.Where( d => d.ContainsKey( "some key" ) )
.Select( d => d["some key"] );
此查询首先识别序列中的哪些字典包含指定的键,然后为每个字典检索给定键的值。
这不如使用TryGetValue()
的循环有效,因为它将执行两次字典访问 - 一次用于Where
,另一次用于Select
。或者,您可以创建一个安全方法,从字典中返回值或默认值,然后筛选出默认值。这消除了重复的字典查找。
public static class DictionaryExt {
public static TValue FindOrDefault<TKey,TValue>(
this Dictionary<TKey,TValue> dic,
TKey key, TValue defaultValue )
{
TValue val;
return dic.TryGetValue( key, out val ) ? val : defaultValue;
}
}
enumeration.Select( d => d.FindOrDefault( "some key", float.NaN ) )
.Where ( f => f != float.NaN );
答案 1 :(得分:2)
LINQ over对象只使用普通的.NET方法,所以你可能不会注意到任何性能差异 - 如果由于一点点开销,LINQ可能会更糟糕,但我不希望它是引人注目。
可能是这样的:
var q = from d in enumeration
where d.ContainsKey("some key")
select d["some key"];
foreach (float f in q)
{
Console.WriteLine(f);
}
答案 2 :(得分:1)
使用TryGetValue
:
float f = 0.0f;
foreach (var dic in enumeration.Where(d => d.TryGetValue("some key", out f))) {
Console.WriteLine(f);
}
答案 3 :(得分:1)
如果在一组不变的词典上经常运行查询...只需将结果捕获到Lookup实例。
//run once
ILookup<string, float> myLookup = enumeration
.SelectMany(d => d)
.ToLookup(kvp => kvp.Key, kvp => kvp.Value);
//run many times
foreach(float f in myLookup["somekey"])
{
Console.WriteLine(f);
}
重要的是要注意,如果查找中没有该键,您将获得一个空IEnumerable<float>
(但不是空)。