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();
一种简单的方法是按顺序压缩:
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;
}
}
}
如果源代码
没有按照顺序准确压缩
的话,这将起作用,因为您没有指定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);
Jodrell的答案是最好的,但实际上他重新实现了System.Linq.Enumerable.Join
。Join还使用查找并保持源的顺序
docIds.Join(
博士,
i=>i,
d=>d.Id,
(i,d)=>d);
您是否确定每个docId
在文档中只发生一次,哪个属性将保存Id
,或者需要选择器Func
?第一个列表是否表示“主列表”?换句话说,第二个列表是代表第一个列表的一部分(或全部)的子集吗?您是否确保每个docId
在docs
中只发生一次,哪个属性将保存Id
或需要选择器Func
?第一个列表是否代表“主列表”?换句话说,第二个列表是代表第一个列表的一部分(或全部)的子集吗?因为Zip
将每个索引(组成一个元组)与相应列表中相同位置的文档组合在一起。然后OrderBy按索引部分对元组进行排序,然后select只从现在已排序的列表中挖掘文档,GetDocsFromDb的结果是无序的,因此您将创建元组,其中Item1
与Item2
无关。我认为这将产生不正确的结果,因为排序时执行的是uppon id而不是索引。因为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;})@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;})这就是我们正在寻找的答案。这正好证明了这一点