2013-03-07 68 views
61

tôi có một danh sách với một số định danh như thế này:Sắp xếp một danh sách từ một danh sách ID

List<long> docIds = new List<long>() { 6, 1, 4, 7, 2 }; 

Morover, tôi có một danh sách các mục <T>, được đại diện bởi các id mô tả ở trên.

List<T> docs = GetDocsFromDb(...) 

tôi cần phải giữ nguyên trật tự trong cả hai bộ sưu tập, do đó các mục trong List<T> phải nằm trong vị trí tương đương so với năm đầu tiên (do tìm kiếm lý do cho điểm động cơ). Và quá trình này không thể thực hiện được trong hàm GetDocsFromDb().

Nếu cần thiết, có thể thay đổi danh sách thứ hai thành một số cấu trúc khác (ví dụ: Dictionary<long, T>), nhưng tôi không muốn thay đổi nó.

Có cách nào đơn giản và hiệu quả để làm điều này "ordenation tùy thuộc vào một số ID" với LINQ?

+0

bạn có chắc chắn rằng mọi 'docId' xảy ra chính xác một lần trong' tài liệu', thuộc tính nào sẽ giữ 'Id' hoặc bộ chọn 'Func ' là bắt buộc? – Jodrell

+0

Danh sách đầu tiên có phải là "danh sách chính" không? Một từ khác, danh sách thứ hai có phải là tập con đại diện cho một phần (hoặc toàn bộ) của danh sách đầu tiên không? – code4life

Trả lời

170
docs = docs.OrderBy(d => docsIds.IndexOf(d.Id)).ToList(); 
+0

@Kaf thats lý do tại sao tôi upvoted quá, không dựa vào biết tài sản ID tài liệu được gọi là 'Id'. Nó không được chỉ định trong câu hỏi. – Jodrell

+0

@ BorjaLópez, một lưu ý nhanh. Bạn đề cập đến hiệu quả trong câu hỏi của bạn. 'IndexOf' là hoàn toàn chấp nhận được cho ví dụ của bạn và tốt đẹp và đơn giản. Nếu bạn có rất nhiều dữ liệu, câu trả lời của tôi có thể phù hợp hơn. http://stackoverflow.com/questions/3663014/why-is-this-list-indexof-code-so-much-faster-than-the-listi-and-manual-compa – Jodrell

+0

Tôi đã đánh giá phương pháp này và một với từ điển (xem bên dưới) và nó gần gấp đôi. –

-1

Một phương pháp đơn giản là để nén với trình tự đặt hàng:

List<T> docs = GetDocsFromDb(...).Zip(docIds, Tuple.Create) 
       .OrderBy(x => x.Item2).Select(x => x.Item1).ToList(); 
+0

lý do tại sao đặt hàng sau mã zip? – Jodrell

+0

Vì 'Zip' kết hợp từng chỉ mục (thành một Tuple) với tài liệu ở cùng vị trí trong danh sách tương ứng.Sau đó, OrderBy sắp xếp các Tuples bằng phần chỉ mục và sau đó lựa chọn chỉ trích các tài liệu của chúng ta từ danh sách được sắp xếp trước. –

+0

nhưng, kết quả của GetDocsFromDb là không có thứ tự, do đó bạn sẽ tạo Tuples trong đó 'Item1' không liên quan đến' Item2'. – Jodrell

5

Vì bạn không chỉ định T,

IEnumerable<T> OrderBySequence<T, TId>(
     this IEnumerable<T> source, 
     IEnumerable<TId> order, 
     Func<T, TId> idSelector) 
{ 
    var lookup = source.ToDictionary(idSelector, t => t); 
    foreach (var id in order) 
    { 
     yield return lookup[id]; 
    } 
} 

là một phần mở rộng chung cho những gì bạn muốn.

Bạn có thể sử dụng phần mở rộng như có lẽ đây,

var orderDocs = docs.OrderBySequence(docIds, doc => doc.Id); 

Một phiên bản an toàn hơn có thể là

IEnumerable<T> OrderBySequence<T, TId>(
     this IEnumerable<T> source, 
     IEnumerable<TId> order, 
     Func<T, TId> idSelector) 
{ 
    var lookup = source.ToLookup(idSelector, t => t); 
    foreach (var id in order) 
    { 
     foreach (var t in lookup[id]) 
     { 
      yield return t; 
     } 
    } 
} 

mà sẽ làm việc nếu source không nén chính xác với order.

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