2012-12-19 49 views
41

public class Person 
{ 
    public string NickName{ get; set; } 
    public string Name{ get; set; } 
} 

var pl = new List<Person>; 

var q = from p in pl 
     where p.Name.First() == 'A' 
     orderby p.NickName 
     select new KeyValuePair<String, String>(p.NickName, p.Name); 

var d1 = q.ToList(); // Gives List<KeyValuePair<string, string>> 
var d2 = q.ToDictionary(); // Does not compile 

如何獲得詞典<字符串,字符串>?如何編寫一個導致字典的LINQ查詢?

+3

'new Dictionary(d1);'或'd1 = q.ToDictionary(p => p.Key,p => p.Value) – Jodrell

+0

@Jodrell祝你好運編譯'new'語句 – Alex

+1

@Alex,你是對的,沒有'IEnumerable >構造器過載。 – Jodrell

回答

40

您需要爲Dictionary

var d2 = q.ToDictionary(p => p.NickName, p => p.Name); 
5

嘗試以下的綽號鍵指定的值,並且名稱爲價值

var d2 = q.ToDictionary (p => p.NickName, p=>p.Name); 

但要注意,字典不允許重複,所以上面會爲具有相同暱稱的重複記錄拋出錯誤。也許你想使用查找類似於字典,但允許重複

var d2 = q.ToLookup (p => p.NickName, p=>p.Name); 
+0

指定一個KeyValuePair的鍵是關鍵,它的值是一個很像Captain Obvious的代碼(它應該是隱含的,恕我直言),但似乎解決了這個問題,謝謝。 – Ivan

+0

使其隱含不適用於所有類型的序列。它僅適用於KeyValuePair上的序列,但是之後您需要使用另一個圖層來生成keyvaluepair。 – Tilak

+0

@Ivan但是,實際上不需要使中間'List >',只是你在查詢結束的顯式語法。正如我的答案。您也可以放鬆訂單。 – Jodrell

8

編輯

如果你真的覺得你需要從IEnumerable<KeyValuePair<TKey, TValue>>得到一個Dictionary暗示你可以添加這個擴展。

public static IDictionary<TKey, ToValue> ToDictionary<TKey, TValue>(
    this IEnumerable<KeyValuePair<TKey, TValue>> source) 
{ 
    return source.ToDictionary(p => p.Key, p => p.Value); 
} 

然後,你可以在任何IEnumerable<KeyValuePair<TKey, TValue>>致電ToDictionary()

EDIT 2

如果你正期待重複,那麼你也可以創建一個ToLookup()擴展。

public static ILookup<TKey, TValue> ToLookup<TKey, TValue>(
    this IEnumerable<KeyValuePair<TKey, TValue>> source) 
{ 
    return source.ToLookup(p => p.Key, p => p.Value); 
} 

或者,如果你真的想放棄的結果,你可以爲ToDictionary添加過載。

public static IDictionary<TKey, ToValue> ToDictionary<TKey, TValue>(
    this IEnumerable<KeyValuePair<TKey, TValue>> source, 
    Func<<IEnumerable<TValue>, TValue> selector) 
{ 
    return source 
     .Lookup(p => p.Key, p => p.Value); 
     .ToDictionary(l => l.Key, l => selector(l)); 
} 

如果隨意丟棄所有,但「第一次」(這是什麼意思沒有OrderBy)項目,你可以使用這個擴展這樣的,

pairs.ToDictionary(v => v.First()); 

總體而言,你可以刪除你的大部分代碼,並做,

var q = from p in pl 
     where p.Name.First() == 'A'; 
var d = q.ToDictionary(p => p.NickName, p => p.Name); 

如果可能有重複,do

var d = q.ToLookup(p => p.NickName, p => p.Name); 

但要注意,這個返回一個ILookup<TKey, TElement>,在Item索引,其中,返回IEnumerable<TElement>這樣你就不會丟棄數據。

+0

+1爲擴展方法 - 這正是我所做的 – sq33G

12

字典不能包含多個相同的密鑰,所以您應該確保(或知道)情況並非如此。你可以使用GroupBy,以確保它:

Dictionary<string, string> dict = pl 
     .Where(p => p.Name.First() == 'A') 
     .GroupBy(p => p.NickName) 
     .ToDictionary(g => g.Key, g => g.First().Name); 
+0

爲什麼不''ToLookup()'?你應該在子查詢中用'Nickname'命令,當你已經用'Nickname'分組時? – Jodrell

+0

@Jodrell:爲什麼要'查看'? OP明確要求字典。是的,'OrderBy'是多餘的(如在OP的代碼中)。我會刪除它。 –

+0

因爲我不能想到丟棄數據的情況,因爲它列舉的方式非常合理。 「IGrouping」上的'OrderBy'可能會使其不那麼簡單。 – Jodrell

0

我意識到,這是標有,但我是從字面上只是試圖找出如何在昨天做了這一點,所以我想我會分享如何你可以在VB中做這個:

Public Class Person 
    Property NickName As String 
    Property Name As String 
End Class 

Sub Main() 
    Dim p1 As New List(Of Person) 

    '*** Fill the list here *** 

    Dim q = (From p In p1 
      Where p.Name.First = "A" 
      Select p.NickName, p.Name).ToDictionary(
              Function(k) k.NickName, 
              Function(v) v.Name) 
End Sub 
+0

但是,在VB中不需要中間的'KeyValuePair'或'OrderBy'。 – Jodrell

+0

的確如此。我剛剛從問題中拿出代碼,將它轉換爲VB,然後添加了「ToDictionary」部分。 :) – bhamby