2010-10-28 35 views
48

Cho haiIEnumerable s có cùng kích thước, làm thế nào tôi có thể chuyển nó sang mộtDictionarysử dụng LINQ?Bản đồ hai danh sách vào một cuốn từ điển trong C#

IEnumerable<string> keys = new List<string>() { "A", "B", "C" }; 
IEnumerable<string> values = new List<string>() { "Val A", "Val B", "Val C" }; 

var dictionary = /* Linq ? */; 

Và sản lượng dự kiến ​​là:

A: Val A 
B: Val B 
C: Val C 

Tôi tự hỏi nếu có một số cách đơn giản để đạt được điều đó.

Và tôi có nên lo lắng về hiệu suất không? Nếu tôi có bộ sưu tập lớn thì sao?


tôi không nếu có một cách dễ dàng hơn để làm điều đó, hiện nay tôi đang làm như thế này:

Tôi có một phương pháp mở rộng đó sẽ lặp các IEnumerable cung cấp cho tôi các phần tử và các chỉ số con số.

public static class Ext 
{ 
    public static void Each<T>(this IEnumerable els, Action<T, int> a) 
    { 
     int i = 0; 
     foreach (T e in els) 
     { 
      a(e, i++); 
     } 
    } 
} 

Và tôi có một phương thức sẽ lặp lại một trong các Liệt kê và với chỉ mục truy lục phần tử tương đương trên Số khác.

public static Dictionary<TKey, TValue> Merge<TKey, TValue>(IEnumerable<TKey> keys, IEnumerable<TValue> values) 
{ 
    var dic = new Dictionary<TKey, TValue>(); 

    keys.Each<TKey>((x, i) => 
    { 
     dic.Add(x, values.ElementAt(i)); 
    }); 

    return dic; 
} 

Sau đó, tôi sử dụng nó như:

IEnumerable<string> keys = new List<string>() { "A", "B", "C" }; 
IEnumerable<string> values = new List<string>() { "Val A", "Val B", "Val C" }; 

var dic = Util.Merge(keys, values); 

Và đầu ra là chính xác:

A: Val A 
B: Val B 
C: Val C 

Trả lời

101

Với .NET 4.0 (hoặc phiên bản 3.5 của System.Interactive từ Rx), bạn có thể sử dụng Zip():

var dic = keys.Zip(values, (k, v) => new { k, v }) 
       .ToDictionary(x => x.k, x => x.v); 
+0

Thumbs up for .Zip. Vui mừng nó đã làm cho nó vào BCL. Tôi đã có phiên bản của riêng tôi trong một thời gian. – spender

+1

@spender - Ngay cả khi bạn tự tạo, tôi sẽ lấy nó từ [Eric Lipperts Blog] (http://blogs.msdn.com/b/ericlippert/archive/2009/05/07/zip-me-up. aspx) – Oliver

+1

Đáng tiếc là cần có phương thức 'Zip'. Nếu chỉ có nhiều ngôn ngữ được gõ tĩnh sẽ hỗ trợ các tham số chung của vectơ, 'Select' sẽ xử lý điều này (như' map' trong sơ đồ). – leppie

20

Hoặc dựa trên ý tưởng của bạn, LINQ bao gồm quá tải Select() cung cấp chỉ mục. Kết hợp với thực tế là values hỗ trợ truy cập bởi chỉ số, người ta có thể làm như sau:

var dic = keys.Select((k, i) => new { k, v = values[i] }) 
       .ToDictionary(x => x.k, x => x.v); 

(Nếu values được giữ như List<string>, có nghĩa là ...)

+0

Ồ, đẹp quá! Tôi đã tìm kiếm chính xác điều đó. LINQ là tiện dụng, nhưng mã bạn cần phải viết với nó trông thực sự khó hiểu IMO. – Nyerguds

7

Tôi thích cách tiếp cận này:

var dict = 
    Enumerable.Range(0, keys.Length).ToDictionary(i => keys[i], i => values[i]); 
0

Nếu bạn sử dụng MoreLINQ, bạn cũng có thể sử dụng nó ToDictionary phương pháp khuyến nông trên tạo ra trước đó KeyValuePair s:

var dict = Enumerable 
    .Zip(keys, values, (key, value) => KeyValuePair.Create(key, value)) 
    .ToDictionary(); 

Cũng cần lưu ý rằng việc sử dụng phương pháp mở rộng là Zip là an toàn đối với các bộ sưu tập nhập có độ dài khác nhau.

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