C# 从另一个列表ID对列表进行排序

C# 从另一个列表ID对列表进行排序,c#,linq,sorting,collections,C#,Linq,Sorting,Collections,我有一个带有如下标识符的列表: List<long> docIds = new List<long>() { 6, 1, 4, 7, 2 }; List docIds=newlist(){6,1,4,7,2}; 此外,我还有另一个项目列表,由上面描述的ID表示 List<T> docs = GetDocsFromDb(...) List docs=GetDocsFromDb(…) 我需要在两个集合中保持相同的顺序,以便列表中的项目必须与第一个集合中的项

我有一个带有如下标识符的列表:

List<long> docIds = new List<long>() { 6, 1, 4, 7, 2 };
List docIds=newlist(){6,1,4,7,2};
此外,我还有另一个
项目列表,由上面描述的ID表示

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

如果需要,可以将第二个列表更改为其他结构(例如,Dictionary),但我不想更改它


是否有任何简单有效的方法可以使用LINQ实现“根据某些ID进行排序”?

一种简单的方法是使用排序顺序进行压缩:

docs = docs.OrderBy(d => docsIds.IndexOf(d.Id)).ToList();
List<T> docs = GetDocsFromDb(...).Zip(docIds, Tuple.Create)
               .OrderBy(x => x.Item2).Select(x => x.Item1).ToList();
List docs=GetDocsFromDb(…).Zip(docid,Tuple.Create)
.OrderBy(x=>x.Item2).Select(x=>x.Item1.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];
    }
}

更安全的版本可能是

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;
        }
    }
}
IEnumerable OrderBySequence(
这是一个数不清的来源,
i数列顺序,
函数(idSelector)
{
var lookup=source.ToLookup(idSelector,t=>t);
foreach(顺序中的变量id)
{
foreach(查找[id]中的var t)
{
收益率t;
}
}
}

如果
源代码
不完全按照
顺序压缩
,Jodrell的答案是最好的,但实际上他重新实现了
System.Linq.Enumerable.Join
。Join还使用查找并保持源的顺序

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

您是否确定每个
docId
文档中只发生一次,哪个属性将保存
Id
,或者需要选择器
Func
?第一个列表是否表示“主列表”?换句话说,第二个列表是代表第一个列表的一部分(或全部)的子集吗?因为
Zip
将每个索引(组成一个元组)与相应列表中相同位置的文档组合在一起。然后OrderBy按索引部分对元组进行排序,然后select只从现在已排序的列表中挖掘文档,GetDocsFromDb的结果是无序的,因此您将创建元组,其中
Item1
Item2
无关。我认为这将产生不正确的结果,因为排序时执行的是uppon id而不是索引。@BorjaLópez,请注意。你在问题中提到了效率
IndexOf
对于您的示例来说是完全可以接受的,而且非常简单。如果你有很多数据,我的答案可能更合适@迪尼森科太棒了。非常感谢;这正是我想要的。如果文档中的元素在排序列表中没有ID,则不起作用效率很低-正在为源集合中的每个元素调用IndexOf,OrderBy必须对元素进行排序。@Jodrell的解决方案要快得多。@DanHunex如果您需要不存在的Id出现在列表的末尾,您可以这样做:.OrderBy(d=>{var index=docIds.IndexOf(d.Id);if(index=-1)index=docIds.Count;return index;})这就是我们正在寻找的答案。这正好证明了Join太难理解了,因为每个人都认为重写它更容易。我使用了这个解决方案,它成功了。就这样,我必须使方法和类都是静态的。
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;
        }
    }
}