从其他列表ID中排序列表

Bor*_*pez 118 c# linq sorting collections

我有一个包含这样的标识符的列表:

List<long> docIds = new List<long>() { 6, 1, 4, 7, 2 };
Run Code Online (Sandbox Code Playgroud)

Morover,我有另一个<T>项目列表,由上述id表示.

List<T> docs = GetDocsFromDb(...)
Run Code Online (Sandbox Code Playgroud)

我需要在两个集合中保持相同的顺序,以便项目List<T>必须与第一个中的位置相同(由于搜索引擎评分原因).而且这个过程不能在GetDocsFromDb()函数中完成.

如有必要,可以将第二个列表更改为其他结构(Dictionary<long, T>例如),但我不想更改它.

是否有任何简单有效的方法来使用LINQ进行"取决于某些ID"的"ordenation"?

Den*_*nko 283

docs = docs.OrderBy(d => docsIds.IndexOf(d.Id)).ToList();
Run Code Online (Sandbox Code Playgroud)

  • @BorjaLópez,快速笔记。您在问题中提到效率。对于您的示例,`IndexOf`是完全可以接受的,并且简洁明了。如果您有大量数据,我的答案可能更适合。http://stackoverflow.com/questions/3663014/why-is-this-list-indexof-code-so-much-faster-than-the-listi-and-manual-compa (3认同)
  • 如果文档中的元素在排序列表中没有 id,则不起作用 (3认同)
  • @DenysDenysenko棒极了.非常感谢; 正是我在寻找的东西. (2认同)
  • 效率很低-为源集合中的每个元素调用IndexOf,并且OrderBy必须对元素进行排序。@Jodrell的解决方案要快得多。 (2认同)
  • @DanHunex如果你需要不存在的id出现在列表的末尾,你可以这样做: .OrderBy(d=&gt; { var index = docIds.IndexOf(d.Id); if (index == -1) index = docIds.Count;返回索引;}) (2认同)

Jod*_*ell 17

既然你没有指定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];
    }
}
Run Code Online (Sandbox Code Playgroud)

是您想要的通用扩展.

您也许可以使用这样的扩展名,

var orderDocs = docs.OrderBySequence(docIds, doc => doc.Id);
Run Code Online (Sandbox Code Playgroud)

更安全的版本可能是

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果source不完全拉链,它将工作order.


Kla*_*zey 10

Jodrell 的回答是最好的,但实际上他重新实现了System.Linq.Enumerable.Join. Join 也使用 Lookup 并保持源的顺序。

    docIds.Join(
      docs,
      i => i,
      d => d.Id,
      (i, d) => d);
Run Code Online (Sandbox Code Playgroud)

  • 这恰恰证明了 Join 太难理解了,因为大家都认为重写它更容易。 (6认同)