从枚举中的多个词典中选择一个值

时间:2010-06-03 21:28:33

标签: c# linq

如果我有一个字典的枚举

IEnumerable<IDictionary<string, float>> enumeration

我可以对它执行Linq查询,以便我可以使用相同的键从枚举中的每个字典中选择一个值吗?

我可以循环执行此操作:

float f;
foreach (var dictionary in enumeration)
{
    if (dictionary.TryGetValue("some key", out f))
    {
        Console.WriteLine(f);
    }
}

(最终的计划是将查询的性能与等效的嵌套循环语句进行比较(枚举本身由另一个查询或一组等效的循环组成)。)

4 个答案:

答案 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>(但不是空)。