2012-12-19 30 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 

Cách nhận từ điển < chuỗi, chuỗi >?Làm thế nào để viết một truy vấn LINQ dẫn đến một từ điển?

+3

làm thế nào về 'từ điển mới (d1);' hoặc 'd1 = q.ToDictionary (p => p.Key, p => p.Value);' – Jodrell

+0

@Jodrell chúc may mắn biên dịch câu lệnh 'mới' – Alex

+1

@ Alex, bạn nói đúng, không có 'IEnumerable > 'quá tải contructor. – Jodrell

Trả lời

40

Bạn cần phải xác định các giá trị cho Dictionary

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

Hãy thử sau cho NickName như Key, và từ tên chính thức Giá trị

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

Nhưng lưu ý từ điển mà không cho phép trùng lặp, vì vậy ở trên ý lỗi ném cho các bản ghi trùng lặp có cùng biệt hiệu. Có lẽ bạn muốn sử dụng Lookup đó là tương tự như từ điển, nhưng cho phép bản sao

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

Chỉ định khóa của KeyValuePair là khóa và giá trị của nó là giá trị trông rất giống mã của Captain Obvious (nó thực sự nên được tạo ra, IMHO) nhưng dường như giải quyết được vấn đề, cảm ơn. – Ivan

+0

làm cho ẩn sẽ không hoạt động đối với tất cả các loại chuỗi. Nó sẽ làm việc chỉ cho chuỗi trên KeyValuePair, nhưng sau đó bạn sẽ yêu cầu một lớp ở giữa để tạo keyvaluepair. – Tilak

+0

@Ivan nhưng, thực sự không cần phải tạo danh sách 'Danh sách > trung gian ', chỉ cho bạn cú pháp rõ ràng ở cuối truy vấn của bạn. Như trong câu trả lời của tôi. Bạn cũng có thể mất trật tự. – Jodrell

8

EDIT

Nếu bạn thực sự cảm thấy bạn cần phải nhận được từ IEnumerable<KeyValuePair<TKey, TValue>> đến một Dictionary ngầm bạn có thể thêm phần mở rộng này.

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

Sau đó, bạn có thể gọi ToDictionary() trên bất kỳ IEnumerable<KeyValuePair<TKey, TValue>> nào.

EDIT 2

Nếu bạn đang dự đoán bản sao sau đó bạn có thể tạo ra một phần mở rộng ToLookup() quá.

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

Hoặc, nếu bạn thực sự muốn hủy kết quả, bạn có thể thêm quá tải cho 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)); 
} 

Nếu bạn tùy tiện vứt bỏ tất cả, nhưng "đầu tiên" (có nghĩa là gì mà không có một OrderBy) mục, bạn có thể sử dụng phần mở rộng này như thế này,

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

Nhìn chung, bạn có thể xóa hầu hết mã của bạn và làm,

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

Nếu có thể trùng lặp, do

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

nhưng lưu ý, đây trả về một ILookup<TKey, TElement>, indexer Item trong đó trả về một IEnumerable<TElement> do đó bạn không hủy dữ liệu.

+0

+1 cho phương pháp mở rộng - đó chính xác là những gì tôi làm – sq33G

12

Từ điển không thể chứa nhiều khóa bằng nhau, vì vậy bạn nên đảm bảo (hoặc biết) rằng đây không phải là trường hợp.Bạn có thể sử dụng GroupBy để đảm bảo nó:

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

Tại sao không phải 'ToLookup()'? Bạn có nên đặt hàng bằng 'Biệt danh' trong truy vấn phụ khi bạn đã nhóm theo' Biệt hiệu 'không? – Jodrell

+0

@Jodrell: Tại sao 'ToLookup'? OP yêu cầu một từ điển một cách rõ ràng. Có, 'OrderBy' là thừa (như trong mã OP). Tôi sẽ gỡ bỏ nó. –

+0

Bởi vì tôi không thể nghĩ ra một tình huống trong đó loại bỏ dữ liệu vì cách liệt kê dữ liệu của nó có ý nghĩa nhiều. Một 'OrderBy' trên' IGrouping' có thể làm cho nó trở nên kém cỏi hơn. – Jodrell

0

tôi nhận ra rằng đây đã được gắn thẻ với , nhưng tôi đã theo nghĩa đen chỉ cố gắng tìm ra cách để làm điều này trong ngày hôm qua, vì vậy tôi nghĩ tôi sẽ chia sẻ cách bạn cũng sẽ làm điều này trong 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

Nhưng, bạn không cần thứ hai 'KeyValuePair' hoặc 'OrderBy' trong VB. – Jodrell

+0

Đúng vậy. Tôi chỉ lấy mã từ câu hỏi, chuyển đổi nó thành VB, và sau đó thêm phần 'ToDictionary'. :) – bhamby

Các vấn đề liên quan