다른 목록 ID에서 목록 정렬 표시됩니다. List<T> docs = GetDocsFromDb(…) 두 컬렉션 모두에서 동일한

다음과 같은 식별자가있는 목록이 있습니다.

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

Morover, 다른 <T>항목 목록 이 있으며 위에서 설명한 ID로 표시됩니다.

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

두 컬렉션 모두에서 동일한 순서를 유지 List<T>해야하므로 (검색 엔진 점수 이유로 인해) 항목 이 첫 번째 항목 과 동일한 위치 에 있어야합니다. 그리고이 과정은 GetDocsFromDb()기능 에서 수행 할 수 없습니다 .

필요한 경우 두 번째 목록을 다른 구조 ( Dictionary<long, T>예 :)로 변경할 수 있지만 변경하지 않는 것이 좋습니다.

LINQ를 사용하여 “일부 ID에 따른 조정”을 수행하는 간단하고 효율적인 방법이 있습니까?



답변

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

답변

당신은 지정하지 않기 때문에 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];
    }
}

원하는 것을위한 일반적인 확장입니다.

아마도 이런 식으로 확장을 사용할 수 있습니다.

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

더 안전한 버전은

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

source와 정확히 압축되지 않으면 작동합니다 order.


답변

Jodrell의 답변이 가장 좋지만 실제로 그는 다시 구현했습니다 System.Linq.Enumerable.Join. Join은 또한 Lookup을 사용하고 소스 순서를 유지합니다.

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

답변

간단한 접근 방법 중 하나는 주문 순서로 압축하는 것입니다.

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