对一个列表进行另一个排序


73

我有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风格的解决方案,我总是可以希望。

任何帮助是最感激的。


5
您是否考虑过在两个列表之间执行linq连接然后执行排序?
RQDQ 2010年

提示:您需要将原始订单另存为字典:id 2索引。
Hamish Grubijan

Answers:


119

另一个LINQ方法:

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

7
我的个人经验是,Linq的性能通常比许多人认为的要好得多,在大多数情况下,它只是语法糖,最终执行与其他代码相同的操作,因此您通常不会感觉到差异。实际上,对于这种特殊情况,我只知道它可以正常工作,我想如果它不能很好地执行,那么您将不得不选择一个完全不同的数据结构,因为这种完整列表联接将始终需要一些时间,无论您如何执行。
Simon D.

25

一种方法是:

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都将在项目列表中存在一个对应的项目...
Justin Lang

1
order.Where(d.ContainsKey).Select(...)或具有使用TryGetValue的较长函数的Select / SelectMany解决了该问题。
吉米

15

不是这个确切问题的答案,但是如果您有两个数组,则有一个重载Array.Sort,需要对数组进行排序,并将数组用作“键”

https://msdn.microsoft.com/zh-CN/library/85y6y2d3.aspx

Array.Sort方法(数组,数组)
基于第一个Array中的键,使用每个键的IComparable实现对一对一维Array对象(一个包含键,另一个包含对应的项)进行排序。


1
任何想法如何使列表工作吗?我在这里是因为我必须使用列表,并且不能使用这种漂亮的数组排序功能。
Bitterblue '17

9

Join如果要匹配精确的整数,则为最佳选择(如果未找到匹配项,则为空序列)。如果您只想获取其他列表的排序顺序(并且假设两个列表中的元素数相等),则可以使用Zip

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

可读性强。


重要说明:这要求ints列表必须排在第一位。接受的答案不是。
Thorarin

@Thorarin不,我想。为什么这么说 ints无论如何我们都进行排序以获得排序顺序,因此不必首先将int排序。
nawfal

@Thorarin,那么还有其他问题。我对自己的代码有把握:)
nawfal

1
它绝对不能解决OP描述的问题。您的代码实际上不会评估对象的ID属性。如何将东西摆放正确的顺序?
Thorarin

@Thorarin我在回答中明确指出了Join可以解决一种问题。Zip是为了别的东西。标题是“按另一个收藏的顺序对一个收藏进行排序”,对于绝大多数人来说,这暗示着我在回答中所追求的。我只是留下了一个替代答案,可能会在将来帮助类似问题的人。当然,如果排序基于id,则还必须指定一个适当的比较器(在中OrderBy
nawfal

4

这是一个扩展方法,它封装了Simon D.对任何类型的列表的响应

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);

0

一种可能的解决方案:

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

注意:如果您使用In-Memory列表,则不适用于IQueryable类型,因为IQueryable它不包含以下内容的定义:IndexOf


-1

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


2
请不要仅将代码发布为答案,还请提供解释代码的作用以及如何解决问题的方法。带有解释的答案通常更有用,而且质量更高,并且更有可能吸引投票。
Dima Kozhevin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.