34

When using linq and you have

c.Sort()

Is there any good inline way of defining a Comparison and/or IComparer class without actually having to create a separate class?

Tim Coker
  • 6,484
  • 2
  • 31
  • 62
Daniel
  • 16,026
  • 18
  • 65
  • 89

5 Answers5

59

That's one of the uses of lambda expressions:

c.Sort( (x,y) => x.A.CompareTo(y.A))

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
ckarras
  • 4,946
  • 2
  • 33
  • 37
  • 1
    I don't think this will work for IComparer as the lamda should return int rather than bool. – Daniel Ballinger Nov 02 '09 at 01:33
  • 4
    You are right. This works for IComparison, not for IComparable. Spend the better part of an hour trying to get something like this to work with the NUnit CollectionAssert.IsOrdered method only to figure out that it doesn't. All of the documentation and articles are confusing because they use the sort method as an example. The sort method has overloads that take either IComparer and IComparison. This only works with the sort method because of the IComparison overload. – Brett Jun 08 '10 at 20:36
  • 3
    @Brett But in the upcoming .NET4.5 you can construct an `IComparer<>` instance from an `IComparison<>` delegate by calling the new static factory method `Comparer<>.Create`. – Jeppe Stig Nielsen Aug 08 '12 at 16:48
17

I have a ProjectionComparer class in MiscUtil, so you can do:

IComparer<Foo> comparer = ProjectionComparer<Foo>.Create(x => x.Name);
c.Sort(comparer);

The code is also in this answer.

You can create a Comparison<T> instance directly with a lambda expression too, but I don't generally like the duplication that involves. Having said which, it often ends up being somewhat shorter...

EDIT: As noted, as of .NET 4.5, use Comparer<T>.Create to do the same thing.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Well, if you look at the accepted answer, it's got redundant information: the "A" part is specified twice. (It also won't compile because it returns a bool instead of an int, but never mind.) That's okay if it's a single simple property, but becomes more of a pain if it's a complicated expression. – Jon Skeet Sep 04 '09 at 22:09
  • @JonSkeet there is something similar in new .NET (utility method for creation IComparer), see my answer – illegal-immigrant Apr 01 '13 at 08:37
  • 1
    @taras.roshko: There is *now*, in .NET 4.5. There wasn't back in 2009 :) – Jon Skeet Apr 01 '13 at 09:05
  • Yes, sure, I mentioned in my answer that finally we have that method in BCL :) – illegal-immigrant Apr 01 '13 at 09:07
15

Jon's answer is great but can be a little bit out of date, with release of .NET 4.5 we now (finally!) have this awesome method Comparer<T>.Create

items.Sort((x, y) => x.Value.CompareTo(y.Value)); //sorting List<T>                
items.OrderBy(x => x, Comparer<Item>.Create((x, y) => x.Value.CompareTo(y.Value))); //sorting IEnumerable<T>

Assuming Item is defined something like:

class Item
{
    public readonly int Key;
    public readonly string Value;

    public Item(int key, string value)
    {
        Key = key;
        Value = value;
    }
}
illegal-immigrant
  • 8,089
  • 9
  • 51
  • 84
7

I've no idea what c.Sort() is in your example, as it can be many things (do you mean List<T>.Sort()?), but one thing that it sure isn't is LINQ. LINQ doesn't have Sort() - it has OrderBy().

That said, the latter also works with IComparer, and there's no way to create an instance of anonymous class implementing the interface "inline", so you'll have to define a class.

For List<T>.Sort(), there is an overload which takes Comparison<T>. Since it's a delegate type, you can use a lambda to provide the function inline:

List<int> xs = ...;
xs.Sort((x, y) => y - x); // reverse sort
Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • "there's no way to create an instance of anonymous class implementing the interface inline" - That depends on your language. F# can do this just fine. – Joel Mueller Jun 08 '10 at 21:22
  • 3
    @Joel: the language is clearly specified in the tags to the question. – Pavel Minaev Jun 09 '10 at 00:52
  • Of course it is. There's also a difference between "no way to do it" and "no way to do it in C#". – Joel Mueller Jun 09 '10 at 16:10
  • 1
    When answering a question which specifies language X for code, both question and answer imply "... in language X", unless explicitly stated otherwise. – Pavel Minaev Jun 09 '10 at 17:31
  • Thanks for pointing out the "OrderBy". For some reason I started on the path of Sort too, and glad I stumbled here - that was so much easier just to specify a quick property name instead of writing a custom comparer. – David Storfer Oct 05 '12 at 16:44
  • 1
    @DavidStorfer, see my answer, in .NET 4.5 we now can use OrderBy simply "specifying property" thanks to the new Comparer.Create method – illegal-immigrant Apr 01 '13 at 08:31
3

If the objects in the List c already implement IComparable you wont need another one. But if you need custom comparison, you can implement IComparer in a nested class. You also can use a lambda expression to create a Comparison method on the fly:

persons.Sort( (person1, person2) => person1.Age.CompareTo( person2.Age ) );

codymanix
  • 28,510
  • 21
  • 92
  • 151