In simple terms, (x, y) => x.CompareTo(y)
is like a one line version of a method - it goes by various names, usually "lambda" or "delegate". You can think of it as a method that is stripped down as much as possible. Here's the full method, I'll talk about stripping it down shortly:
int MyComparer(int x, int y){
return x.CompareTo(y);
}
The list will perform a sort and will call this method every time it wants to make a choice as to which of the two ints it's considering, is larger than the other. How it does the sort is irrelevant, probably quicksort ish, but ultimately it will often want to know whether x is larger, same or smaller than y
You could take that method I wrote up there and call sort with it instead:
yourList.Sort(MyComparer)
So c# has this notion of being able to pass methods round in the same way that it passes variable data around. Typically when you pass a method you're saying "here's some logic you should call when you need to know that thing you want to know" - like a custom sort algorithm trhat you can vary by varying the logic you pass in
In stripping MyComparer down, well.. we know this list is full of ints so we know that x and y are ints, so we can throw the "int" away. We can get rid of the method name too, and because it's just one line we can ditch the curly brackets. The return keyword is unnecessary too because by definition to be useful the single line is going to have to evaluate to something returnable and it shall be returned implicitly. The => separates the parameters from the body logic
(method,parameters) => logic_that_produces_a_value(
So that long winded method can be boiled down to
(x,y) => x.CompareTo(y)
x,y are whatever type the list holds, the result value is a -1, 0 or 1 which list will use to determine how x and y relate sorting wise. They could be called anything; just like when you declare a method MyMethod(int left, int right)
and choose to call the parameters "left" and "right", here we do the same because this is just declaring name parameters - you could easily write (left,right) => left.CompareTo(right)
and it'd work the same
You'll see it a lot in c#, because c# devs are quite focused on representing logic in a compact fashion. Often the most useful way of making something flexible and powerful is to implement some of the logic but then leave it possible for another dev to finish the logic off. Microsoft implemented sorting into list, but they leave it up to us to decide "which is greater or lesser" so we can supply logic that influences sort order. They just mandated "any time we want to know which way round two things are we'll ask you" - which means they don't need to have SortAscending and SortDescending - we just flip the logic and declare that 10 is less than 9 if we want 10 to come first.
LINQ relies on "supply me some logic" heavily - you might be looking for all ints less than 3 in your list:
myList.Where(item => item < 3)
LINQ will loop over the list calling your supplied logic (lambda) here on every item and delivering only those where your lambda is true. item
is one of the list entries, in this case an int. if the list held Person objects, item
would be a Person. To that end I'd recommend calling it p
or person
to make it clearer what it is. This will become important when you start using more complex lambdas like
string[] wantedNames = new [] { "John", "Luke" };
people.Where(p => wantedNames.Any(n => p.Name == n));
This declares multiple names you're looking for then searches the list of people for all those whose name is in the list of wanted names. For every person p, LINQ asks "wantedNames, do Any of your elements return true for this supplied logic" and then it loops over the wantedNames calling the logic you supplied (n, the item from wantedNames is equal to the person name?).
Here you've used two different methods that take custom logic that LINQ calls repeatedly - Where is a method that takes a delegate, and so is Any; the Any operates on the list of names, the Where operates on the list of people so keeping it clear which is a Person p and which is a name string n using variable names is better than using bland names like a and b.
Got more into on your Sort method see the docs:
See List.Sort(Comparer) for more info
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort?view=net-5.0#System_Collections_Generic_List_1_Sort_System_Comparison__0__