2010-06-03 43 views
3

如果我有字典的枚舉選擇一個枚舉內從多個詞典的值

IEnumerable<IDictionary<string, float>> enumeration 

我可以執行它LINQ查詢,這樣我可以由值從每個字典在枚舉使用選擇同樣的鑰匙?

我可以在一個循環做到這一點:

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

(最終的計劃是比較查詢的性能詩句等效嵌套循環語句(本身無論從另一個查詢或等效形成的枚舉。環套))

回答

5

您正在尋找這樣的事情:

IEnumerable<float> vals = enumeration.Where(d => d.ContainsKey("some key")) 
            .Select(d => d["some key"]); 

該查詢首先識別的辭典在SE quence包含指定鍵,然後爲每個獲取的對於給定的關鍵字的值。

這不如使用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); 
2

LINQ在對象只是使用普通的.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); 
} 
1

使用TryGetValue

float f = 0.0f; 
foreach (var dic in enumeration.Where(d => d.TryGetValue("some key", out f))) { 
    Console.WriteLine(f); 
} 
1

如果查詢上不變集字典經常運行...只是捕獲結果的查詢實例。

//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>(但不是空)是很重要的。