views:

626

answers:

4

I can sort a list using Sort or OrderBy. Which one is faster? Are both working on same algorithm?

        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);
        }
    }
A: 

Test it out and let us know.

James
wow ! What a clever answer. :)
Seems like a fair enough answer to me :)
James
It might have been better as a comment, but this is a perfectly valid suggestion.
Marc Gravell
i can't se why some one -1 this... its so easy to test why not just do it instead of asking the question in the first place?
Petoj
@Marc, it's doesn't hit the point (about difference) and don't offer any new/useful info; it's like to answer another questions with "when you figure it out, let me know"
Rubens Farias
@Marc, fair point it probably should have been a comment. However, I think it is a valid response giving the OP has the code they want to test. I was hoping my response would have triggered the OP into actually thinking about ways of testing it or even commented on my answer asking HOW to which I would have responded with something similar to Darin's answer.
James
@Rubens, look at the question...its like going out and buying a car and then asking someone else with a similar car "so how does she drive?". Why not just drive the car yourself and find out :)
James
@James, I got your point, but I still think this doesn't help OP to come any closer to an answer; anyways, ty for discussing your point
Rubens Farias
@Rubens, I would disagree I think it gives the OP the knowledge that they don't need to know the internal workings of LINQ to figure out which is faster. A simple test (like Darin's answer) proves that.
James
@Petoj...my sentiments exactly!
James
+6  A: 

No, they aren't the same algorithm. For starters, the LINQ OrderBy is documented as stable (i.e. if two items have the same Name, they'll appear in their original order).

It also depends on whether you buffer the query vs iterate it several times (LINQ-to-Objects, unless you buffer the result, will re-order per foreach).

For the OrderBy query, I would also be tempted to use:

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

(for {yourchoice} one of CurrentCulture, Ordinal or InvariantCulture).

List<T>.Sort

This method uses Array.Sort, which uses the QuickSort algorithm. This implementation performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.

Enumerable.OrderBy

This method performs a stable sort; that is, if the keys of two elements are equal, the order of the elements is preserved. In contrast, an unstable sort does not preserve the order of elements that have the same key. sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.

Marc Gravell
deleted my incorrect answer. +1.
Jimmeh
+6  A: 

Why not measure it:

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

On my computer when compiled in Release mode this program prints:

Sort: 1162ms
OrderBy: 1269ms


UPDATE:

As suggested by @Stefan here are the results of sorting a big list fewer times:

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

Prints:

Sort: 8965ms
OrderBy: 8460ms

In this scenario it looks like OrderBy performs better.


UPDATE2:

And using random names:

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

Where:

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

Yields:

Sort: 8968ms
OrderBy: 8728ms

Still OrderBy is faster

Darin Dimitrov
....herein lies the reason for my answer.
James
I think, it's much different of sorting a very small list (3 items) 1000000 times, or by sorting a very large list (1000000 items) just a few times. Both is very relevant. In practice, medium size of list (what's medium? ... let's say 1000 items for now) is most interesting. IMHO, sorting lists with 3 items is not very meaningful.
Stefan Steinegger
@Stefan, in reality the list may indeed be more. The point is it demonstrates the speed difference.
James
Nice suggestion @Stefan, I've updated my answer.
Darin Dimitrov
Interesting results. Thank you for taking the time.
Stefan Steinegger
Note that there is a difference between "faster" and "noticably faster". In your last example the difference was about a quarter of a second. Is the user going to notice? Is it unacceptable for the user to wait almost nine seconds for the result? If the answers to both questions are "no" then it really doesn't matter which one you pick from a performance perspective.
Eric Lippert
A: 

I think it's important to note another difference between Sort and OrderBy:

Suppose there exists a Person.CalculateSalary() method, which takes a lot of time, possibly more than even the operation of sorting a large list.

Compare:

1)

    persons.Sort((p1,p2)=> Compare(p1.CalculateSalary(),p2.CalculateSalary()));

2)

    var query = persons.OrderBy(p => p.CalculateSalary()); 

Option 2 may have superior performance, because it only calls the CalculateSalary method n times, whereas the Sort option might call CalculateSalary up to 2*n*log(n) times, depanding on the sort algorithm's success.

Omer Raviv