Подтвердить что ты не робот

Сортировка списка из другого идентификатора списка

У меня есть список с некоторыми идентификаторами вроде этого:

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

Morover, у меня есть еще один список элементов <T>, которые представлены идентификаторами, описанными выше.

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

Мне нужно сохранить один и тот же порядок в обеих коллекциях, так что элементы в List<T> должны находиться в том же положении, что и в первом (из-за ошибок в поисковых системах). И этот процесс не может быть выполнен в функции GetDocsFromDb().

При необходимости можно изменить второй список на некоторую другую структуру (например, Dictionary<long, T>), но я бы предпочел не изменять его.

Есть ли простой и эффективный способ сделать это "упорядочение в зависимости от некоторых идентификаторов" с LINQ?

4b9b3361

Ответ 1

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

Ответ 2

Поскольку вы не указываете 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.

Ответ 3

Ответ Джодрелла самый лучший, но на самом деле он переопределил System.Linq.Enumerable.Join. Join также использует Lookup и сохраняет порядок источника.

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

Ответ 4

Одним простым подходом является zip с последовательностью упорядочения:

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