2013-03-07 96 views
61

我有一些像这样的标识符的列表:排序从另一个列表ID的列表

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

Morover,我的<T>物品,其通过上述的ID表示的另一列表。

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

我必须保持相同的顺序在这两个集合,因此在List<T>的项目必须在相同的位置比第一个(因搜索引擎评分的原因)。这个过程不能在GetDocsFromDb()函数中完成。

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

是否有任何简单而有效的方法来做到这一点“取决于某些ID的定义”与LINQ?

+0

你确定每个'docId'只出现在'docs'一次,什么属性会保存'Id'或将选择器'Func '是必需的? – Jodrell 2013-03-07 15:43:56

+0

第一个列表是否代表“主列表”?换句话说,第二个列表是否是表示第一个列表的一部分(或全部)的子集? – code4life 2013-03-07 16:00:00

回答

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

@卡夫这就是为什么我upvoted太,确实依靠知道文件ID属性被称为'Id'。它没有在问题中指定。 – Jodrell 2013-03-07 16:13:40

+0

@BorjaLópez,快速记录。你在你的问题中提到效率。 'IndexOf'完全可以接受你的例子,又好又简单。如果你有很多数据,我的答案可能会更适合。 http://stackoverflow.com/questions/3663014/why-is-this-list-indexof-code-so-much-faster-than-the-listi-and-manual-compa – Jodrell 2013-03-07 17:20:59

+0

我已经基准这种方法和一个字典(见下文),它几乎快两倍。 – 2014-04-01 05:51:01

-1

一个简单的方法是用排序序列号邮编:

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

为什么订购后拉链? – Jodrell 2013-03-07 16:02:52

+0

因为'Zip'将每个索引(到一个元组)与文档放在相应列表中的相同位置。然后OrderBy通过索引部分对元组进行排序,然后选择从现在排序的列表中挖掘我们的文档。 – 2013-03-07 16:58:01

+0

但是,GetDocsFromDb的结果是无序的,因此您将创建“Item1”与“Item2”无关的元组。 – Jodrell 2013-03-07 17:15:12

5

既然你不指定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拉链,将正常工作。