2010-10-15 109 views
68

我有2个列表对象,其中一个是整数列表,另一个是对象列表,但对象具有ID属性。排序一个列表另一个

我想要做的就是按照与整数列表相同的排序顺序对它的ID列表进行排序。

我一直玩了一段时间,现在试图得到它的工作,到目前为止,还没有喜悦,

这里是我迄今为止...

//************************** 
//*** Randomize the list *** 
//************************** 
if (Session["SearchResultsOrder"] != null) 
{ 
    // save the session as a int list 
    List<int> IDList = new List<int>((List<int>)Session["SearchResultsOrder"]); 
    // the saved list session exists, make sure the list is orded by this 
    foreach(var i in IDList) 
    { 
     SearchData.ReturnedSearchedMembers.OrderBy(x => x.ID == i); 
    } 
} 
else 
{ 
    // before any sorts randomize the results - this mixes it up a bit as before it would order the results by member registration date       
    List<Member> RandomList = new List<Member>(SearchData.ReturnedSearchedMembers); 
    SearchData.ReturnedSearchedMembers = GloballyAvailableMethods.RandomizeGenericList<Member>(RandomList, RandomList.Count).ToList(); 

    // save the order of these results so they can be restored back during postback 
    List<int> SearchResultsOrder = new List<int>(); 
    SearchData.ReturnedSearchedMembers.ForEach(x => SearchResultsOrder.Add(x.ID)); 
    Session["SearchResultsOrder"] = SearchResultsOrder; 
} 

这样做的整点因此当用户搜索会员时,最初他们以随机顺序显示,然后如果他们点击第2页,他们将保持该顺序,并显示下20个结果。

我一直在阅读有关ICompare我可以用作Linq.OrderBy子句中的参数,但我找不到任何简单的示例。

我希望有一个优雅,非常简单的LINQ风格的解决方案,以及我一直希望的。

任何帮助最受赞赏。这样做的

+4

你有没有考虑在两个列表之间执行linq连接,然后进行排序? – RQDQ 2010-10-15 20:39:03

+0

提示:您需要将原始顺序保存为字典:id 2索引。 – 2010-10-15 20:40:06

+3

http://stackoverflow.com/questions/3470098/linq-list-sort-based-on-another-list – goodeye 2012-11-28 00:11:42

回答

116

另一个LINQ的方法:

var orderedByIDList = from i in ids 
         join o in objectsWithIDs 
         on i equals o.ID 
         select o; 
+0

性能如何? – 2010-10-15 21:16:19

+7

我个人的经验是Linq总体来说表现比许多人想象的要好得多,在大多数情况下,它只是语法糖最后执行与其他代码相同的操作,所以你通常不会感觉到差异。 其实,对于这种特殊情况,我只知道它的工作原理,我猜如果它表现不好,那么你将不得不选择一个完全不同的数据结构,因为这个完整列表连接总是需要一些时间,不管你怎么做。 – 2010-10-16 18:50:30

24

方式一:

List<int> order = ....; 
List<Item> items = ....; 

Dictionary<int,Item> d = items.ToDictionary(x => x.ID); 

List<Item> ordered = order.Select(i => d[i]).ToList(); 
+1

可能的重复您假设对于订单列表中的每个int,项目中将存在相应的项目list ... – 2013-05-21 22:17:38

+1

'order.Where(d.ContainsKey).Select(...)'或Select/SelectMany使用TryGetValue更长的函数解决了这个问题。 – Jimmy 2013-05-21 22:57:09

9

Join是最佳人选,如果你想匹配确切的整数(如果没有找到匹配您获得一个空序列)。如果您只想获得其他列表的排序顺序(并且提供的两个列表中的元素数量相同),则可以使用Zip

var result = objects.Zip(ints, (o, i) => new { o, i}) 
        .OrderBy(x => x.i) 
        .Select(x => x.o); 

很可读。

+0

重要提示:这需要首先对ints列表进行排序。接受的答案不是。 – Thorarin 2016-09-28 13:54:39

+0

@Thorarin不,我想。你为什么这么说?我们对ints进行排序以得到排序顺序,因此不必首先对整数进行排序。 – nawfal 2016-09-28 13:57:36

+0

@Thorarin,那么别的东西是错误的。我确信我的代码:) – nawfal 2016-09-28 14:17:40

4

这是一个扩展方法,它为任何类型的列表封装Simon D.'s response

public static IEnumerable<TResult> SortBy<TResult, TKey>(this IEnumerable<TResult> sortItems, 
                 IEnumerable<TKey> sortKeys, 
                 Func<TResult, TKey> matchFunc) 
{ 
    return sortKeys.Join(sortItems, 
         k => k, 
         matchFunc, 
         (k, i) => i); 
} 

用法是一样的东西:

var sorted = toSort.SortBy(sortKeys, i => i.Key); 
13

不回答这个确切的问题,但如果你有两个阵列,有可能采取的数组进行排序的Array.Sort超载,以及用作'钥匙'的阵列

https://msdn.microsoft.com/en-us/library/85y6y2d3.aspx

的Array.Sort方法(Array,阵列)
对一对一维数组(一个包含键 ,另一个包含对应的项目)的基础上的钥匙, 使用所述第一阵列每个密钥的IComparable实现。

+0

任何想法如何使这个工作的列表?我在这里**因为**我必须使用列表,不能使用这个漂亮的数组排序的东西。 – Bitterblue 2017-08-11 08:43:50

0

一个可能的解决方案:

myList = myList.OrderBy(x => Ids.IndexOf(x.Id)).ToList(); 

注:使用这​​个,如果你用In-Memory名单的工作,不适合IQueryable类型的工作,因为IQueryable不包含定义IndexOf