Sắp xếp danh sách từ ID danh sách khác


149

Tôi có một danh sách với một số định danh như thế này:

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

Morover, tôi có một danh sách các <T>mục khác, được thể hiện bằng các id được mô tả ở trên.

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

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

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

Có cách nào đơn giản và hiệu quả để thực hiện "sự thay đổi tùy thuộc vào một số ID" với LINQ không?


Bạn có chắc chắn rằng mỗi lần docIdxảy ra chính xác một lần docs, tài sản nào sẽ giữ Idhoặc sẽ Func<T, long>được yêu cầu chọn ?
Jodrell

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

Câu trả lời:


331
docs = docs.OrderBy(d => docsIds.IndexOf(d.Id)).ToList();

@Kaf đó là lý do tại sao tôi nâng cấp quá, không phụ thuộc vào việc biết thuộc tính ID tài liệu được gọi Id. Nó không được chỉ định trong câu hỏi.
Jodrell

3
@ BorjaLópez, một ghi chú nhanh. Bạn đề cập đến hiệu quả trong câu hỏi của bạn. IndexOflà hoàn toàn chấp nhận cho ví dụ của bạn và tốt đẹp và đơn giản. Nếu bạn có nhiều dữ liệu, câu trả lời của tôi có thể phù hợp hơn. stackoverflow.com/questions/3663014/iêu
Jodrell

2
@DenysDenysenko Tuyệt vời. Cám ơn rất nhiều; Chính xác những gì tôi đang tìm kiếm.
lửa lụa

3
không hoạt động nếu bạn có các yếu tố trong tài liệu không có id trong danh sách đặt hàng
Dan Hunex

4
Khá kém hiệu quả - IndexOf đang được gọi cho mọi phần tử trong bộ sưu tập nguồn và OrderBy phải đặt hàng các phần tử. Giải pháp của @Jodrell nhanh hơn nhiều.
sdds

25

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 tiện ích mở rộng như thế này, có lẽ,

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;
        }
    }
}

Nó sẽ hoạt động nếu sourcekhông zip chính xác với order.


Tôi đã sử dụng giải pháp này và nó đã làm việc. Chỉ là, tôi phải làm cho phương thức tĩnh và lớp tĩnh.
vinmm

5

Câu trả lời của Jodrell là tốt nhất, nhưng thực ra anh ta đã thực hiện lại System.Linq.Enumerable.Join. Tham gia cũng sử dụng Tra cứu và tiếp tục đặt hàng nguồn.

    docIds.Join(
      docs,
      i => i,
      d => d.Id,
      (i, d) => d);

Đó là câu trả lời mà chúng tôi đang tìm kiếm
Orace

2
Điều này chỉ chứng tỏ rằng Tham gia quá khó hiểu vì mọi người đều đồng ý rằng việc viết lại nó dễ dàng hơn.
PRman

-3

Một cách tiếp cận đơn giản là zip 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();

Tại sao đặt hàng sau một zip?
Jodrell

Bởi vì Zipkết hợp mỗi chỉ mục (thành một Tuple) với tài liệu ở cùng một vị trí trong danh sách tương ứng. Sau đó, OrderBy sắp xếp các Tuples theo phần chỉ mục và sau đó phần chọn sẽ đào các tài liệu của chúng ta từ danh sách đã được sắp xếp.
Albin Sunnanbo

tuy nhiên, kết quả của GetDocsFromDb không được sắp xếp theo thứ tự nên bạn sẽ tạo Tuples ở những nơi Item1không liên quan Item2.
Jodrell

1
Tôi nghĩ rằng điều này sẽ tạo ra kết quả không chính xác kể từ khi đặt hàng thực hiện id uppon chứ không phải chỉ mục.
Michael Logutov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.