C#Sort和OrderBy比较

时间:2009-12-02 12:45:00

标签: c# .net performance sorting sql-order-by

我可以使用Sort或OrderBy对列表进行排序。哪一个更快?两者都是一样的 算法

List<Person> persons = new List<Person>();
persons.Add(new Person("P005", "Janson"));
persons.Add(new Person("P002", "Aravind"));
persons.Add(new Person("P007", "Kazhal"));

1

persons.Sort((p1,p2)=>string.Compare(p1.Name,p2.Name,true));

2

var query = persons.OrderBy(n => n.Name, new NameComparer());

class NameComparer : IComparer<string>
{
    public int Compare(string x,string y)
    {
      return  string.Compare(x, y, true);
    }
}

7 个答案:

答案 0 :(得分:112)

不,它们不是同一种算法。对于初学者,LINQ OrderBy被记录为 stable (即如果两个项目具有相同的Name,则它们将以原始顺序出现。)

它还取决于您是否缓冲查询与多次迭代(LINQ-to-Objects,除非您缓冲结果,将按foreach重新排序。)

对于OrderBy查询,我也很想使用:

OrderBy(n => n.Name, StringComparer.{yourchoice}IgnoreCase);

{yourchoice} CurrentCultureOrdinalInvariantCulture中的一个{{1}}。

List<T>.Sort

  

此方法使用Array.Sort,其中   使用QuickSort算法。这个   实现执行不稳定   分类;也就是说,如果有两个元素   平等,他们的订单可能不是   保存。相比之下,稳定的排序   保留元素的顺序   是平等的。

Enumerable.OrderBy

  

此方法执行稳定排序;也就是说,如果两个元素的键相等,则保留元素的顺序。相反,不稳定的排序不会保留具有相同键的元素的顺序。   分类;也就是说,如果有两个元素   平等,他们的订单可能不是   保存。相比之下,稳定的排序   保留元素的顺序   是平等的。

答案 1 :(得分:85)

为什么不测量它:

class Program
{
    class NameComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            return string.Compare(x, y, true);
        }
    }

    class Person
    {
        public Person(string id, string name)
        {
            Id = id;
            Name = name;
        }
        public string Id { get; set; }
        public string Name { get; set; }
    }

    static void Main()
    {
        List<Person> persons = new List<Person>();
        persons.Add(new Person("P005", "Janson"));
        persons.Add(new Person("P002", "Aravind"));
        persons.Add(new Person("P007", "Kazhal"));

        Sort(persons);
        OrderBy(persons);

        const int COUNT = 1000000;
        Stopwatch watch = Stopwatch.StartNew();
        for (int i = 0; i < COUNT; i++)
        {
            Sort(persons);
        }
        watch.Stop();
        Console.WriteLine("Sort: {0}ms", watch.ElapsedMilliseconds);

        watch = Stopwatch.StartNew();
        for (int i = 0; i < COUNT; i++)
        {
            OrderBy(persons);
        }
        watch.Stop();
        Console.WriteLine("OrderBy: {0}ms", watch.ElapsedMilliseconds);
    }

    static void Sort(List<Person> list)
    {
        list.Sort((p1, p2) => string.Compare(p1.Name, p2.Name, true));
    }

    static void OrderBy(List<Person> list)
    {
        var result = list.OrderBy(n => n.Name, new NameComparer()).ToArray();
    }
}

在我的计算机上,在发布模式下编译时,该程序将打印:

Sort: 1162ms
OrderBy: 1269ms

更新:

正如@Stefan所建议的那样,对大型列表进行较少次排序的结果如下:

List<Person> persons = new List<Person>();
for (int i = 0; i < 100000; i++)
{
    persons.Add(new Person("P" + i.ToString(), "Janson" + i.ToString()));
}

Sort(persons);
OrderBy(persons);

const int COUNT = 30;
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < COUNT; i++)
{
    Sort(persons);
}
watch.Stop();
Console.WriteLine("Sort: {0}ms", watch.ElapsedMilliseconds);

watch = Stopwatch.StartNew();
for (int i = 0; i < COUNT; i++)
{
    OrderBy(persons);
}
watch.Stop();
Console.WriteLine("OrderBy: {0}ms", watch.ElapsedMilliseconds);

打印:

Sort: 8965ms
OrderBy: 8460ms

在这种情况下,看起来OrderBy表现更好。


UPDATE2:

使用随机名称:

List<Person> persons = new List<Person>();
for (int i = 0; i < 100000; i++)
{
    persons.Add(new Person("P" + i.ToString(), RandomString(5, true)));
}

其中:

private static Random randomSeed = new Random();
public static string RandomString(int size, bool lowerCase)
{
    var sb = new StringBuilder(size);
    int start = (lowerCase) ? 97 : 65;
    for (int i = 0; i < size; i++)
    {
        sb.Append((char)(26 * randomSeed.NextDouble() + start));
    }
    return sb.ToString();
}

收率:

Sort: 8968ms
OrderBy: 8728ms

Still OrderBy更快

答案 2 :(得分:53)

Darin Dimitrov的回答显示,OrderBy在面对已经排序的输入时比List.Sort略快。我修改了他的代码,因此它重复排序未排序的数据,OrderBy在大多数情况下稍慢。

此外,OrderBy测试使用ToArray强制枚举Linq枚举器,但这显然会返回一个与输入类型({{1)不同的类型(Person[]) }})。因此,我使用List<Person>而非ToList重新进行了测试,并获得了更大的差异:

ToArray

代码:

Sort: 25175ms
OrderBy: 30259ms
OrderByWithToList: 31458ms

答案 3 :(得分:34)

我认为注意SortOrderBy之间的另一个区别非常重要:

假设存在Person.CalculateSalary()方法,这需要花费大量时间;可能甚至超过排序大型列表的操作。

<强>比较

// Option 1
persons.Sort((p1, p2) => Compare(p1.CalculateSalary(), p2.CalculateSalary()));
// Option 2
var query = persons.OrderBy(p => p.CalculateSalary()); 

选项2 可能具有卓越的性能,因为它只调用CalculateSalary方法 n 次,而Sort选项可能会调用{{ 1}}最多2n log(n)次,具体取决于排序算法的成功。

答案 4 :(得分:7)

简而言之:

列表/数组Sort():

  • 不稳定排序。
  • 就地完成。
  • 使用Introsort / Quicksort。
  • 通过提供比较器来完成自定义比较。如果比较昂贵,则它可能比OrderBy()慢(后者允许使用键,请参见下文)。

OrderBy / ThenBy():

  • 稳定排序。
  • 未就地。
  • 使用Quicksort。 Quicksort不是稳定的排序。这是窍门:排序时,如果两个元素具有相同的键,它将比较它们的初始顺序(在排序之前已存储)。
  • 允许使用键(使用lambda)对元素值进行排序(例如:x => x.Id)。在排序之前,首先提取所有密钥。与使用Sort()和自定义比较器相比,这可能会导致更好的性能。

来源: MDSNreference sourcedotnet/coreclr存储库(GitHub)。

上面列出的某些语句基于当前的.NET Framework实现(4.7.2)。将来可能会改变。

答案 5 :(得分:0)

你应该计算OrderBy和Sort方法使用的算法的复杂性。 我记得QuickSort的复杂度为n(log n),其中n是数组的长度。

我也搜索了orderby,但即使在msdn库中也找不到任何信息。 如果你没有任何相同的值和排序只涉及一个属性,我更喜欢使用 Sort()方法;如果不是使用OrderBy。

答案 6 :(得分:-1)

我只想补充一下,orderby更有用。

为什么?

因为我可以这样做

        Dim thisAccountBalances = account.DictOfBalances.Values.ToList
        thisAccountBalances.ForEach(Sub(x) x.computeBalanceOtherFactors())
        thisAccountBalances=thisAccountBalances.OrderBy(Function(x) x.TotalBalance).tolist
        listOfBalances.AddRange(thisAccountBalances)

为何复杂的比较?只需根据字段进行排序。我在这里根据TotalBalance进行排序。

非常简单

我无法通过排序来做到这一点。我想知道为什么。订单执行得很好。

至于速度。它始终是O(n)