按另一个List <t>对List <t>进行排序

时间:2016-04-08 12:13:12

标签: c# linq

我的模特是:

class Person
{
    public int Id {get; set; }
    public string Name {get; set; }
}

我有两个系列。我想像toBeSortedList那样排序etalonList

List<Person> etalonList = new List<Person>()
{
     new Person() { Id=10, Name="Jon"},
     new Person() { Id=4, Name="Ben"},
     new Person() { Id=11, Name="Magnus"},
     new Person() { Id=8, Name="Joseph"},
};

List<Person> toBeSortedList = new List<Person>()
{
     new Person() { Id=11, Name="Magnus"},
     new Person() { Id=4, Name="Ben"},                
     new Person() { Id=10, Name="Jon"},
     new Person() { Id=8, Name="Joseph"},
};

我试过了:

var orderedByIdList = tobeSortedList.OrderBy(x => etalonList.IndexOf(x.Id));

但我遇到了这样的错误:

  

无法转换为&#39; int&#39;到&#39; SOConsoleApplication.Person&#39;

也许你还有其他建议?

5 个答案:

答案 0 :(得分:3)

我首先要从etalonList创建一个字典,以加快排序速度:

int index;
var etalonDictionary = etalonList.ToDictionary(k => k.Id, v => index++);

然后从字典中找回ID并将其用于排序:

var sortedList = toBeSortedList.OrderBy(x => etalonDictionary[x.Id]).ToList();

答案 1 :(得分:2)

List.IndexOf将对象作为参数并返回它的索引。您正在传递int - 值Id。那不编译。

您可以覆盖Equals + GethashCode并传递x而不是x.Id。但在这种情况下我更喜欢List.FindIndex

 var orderedByIdList = toBeSortedList
    .OrderBy(x => etalonList.FindIndex(p => p.Id == x.Id));

以下是覆盖Equals方法,可以使用IndexOf

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        if(ReferenceEquals(obj, this))
            return true;
        Person other = obj as Person;
        if (other == null)
            return false;
        return other.Id == this.Id;
    }

    public override int GetHashCode()
    {
        return Id;
    }
}

现在这也有效:

var orderedByIdList = toBeSortedList
    .OrderBy(x => etalonList.IndexOf(x));

答案 2 :(得分:1)

我猜测etalonList中的某些值在toBeSortedList中不存在,因为在所有其他情况下,这个问题毫无意义:

  1. toBeSortedList的元素未包含在etalonList中。在这种情况下,问题是不明确的;你会如何订购这些新的名单成员?
  2. toBeSortedList包含与etalonList完全相同的成员。在这种情况下,只需返回etalonList或复制它。
  3. 订购toBeSortedList的一种天真但简单的方法如下(注意我假设案例1不可能):

    static IEnumerable<T> OrderBy(this IEnumerable<T> list, IEnumerable<T> guideList)
    {
        foreach (var member in guideList)
        {
            if (toBeSortedList.Contains(member))
                yield return member;
        }
    }
    
    var orderedList = toBeSortedList.OrderBy(etalonList).ToList();
    

    表现不好,但如果列表不是很长,那就应该这样做。

答案 3 :(得分:1)

在这种情况下,你根本不需要定期排序。你可以简单地join带有目标的标准具并投射目标元素。如果标准具不包含所有目标,则可以在排序序列的开头或结尾处连接不存在的项,最终应用一些额外的顺序。

在这两种情况下,您最终都会进行快速O(N)时间复杂度操作。

这是LINQ,它将非现有项放在最后:

var orderedByIdList =
    (from a in etalonList join b in toBeSortedList on a.Id equals b.Id select b)
    .Concat
    (from a in toBeSortedList join b in etalonList on a.Id equals b.Id into b where !b.Any() select a)
    .ToList();

答案 4 :(得分:1)

    public static IEnumerable<T> OrderBy<T>( this IEnumerable<T> list, IEnumerable<T> guide ) {
        var toBeSorted = new HashSet<T>( list );
        return guide.Where( member => toBeSorted.Contains( member ) );
    }