Why custom sorting
A list's Sort() puts numbers from small to large and strings from A to Z. Often you need another order: the highest price first, the shortest word first, or names ordered by their last letter. LINQ has methods for that. Each one takes a lambda that says what to sort each item by. In a file of your own, add using System.Linq;.
The sorting methods
OrderBy(w => w.Length)sorts by what the lambda returns, from small to large.OrderByDescending(s => s)sorts from large to small.ThenBy(n => n)adds a second rule. It only orders items that tie on the first rule.ThenByDescendingis a second rule from large to small.
List<int> scores = new List<int>(new[] {70, 95, 82});
List<int> highFirst = scores.OrderByDescending(s => s).ToList();
List<int> nums = new List<int>(new[] {25, 13, 5, 41, 33});
List<int> byLastDigit = nums.OrderBy(n => n % 10).ThenBy(n => n).ToList();
Printed with string.Join(" ", ...), byLastDigit reads 41 13 33 5 25. The first rule sorts by last digit; the second puts numbers with the same last digit (13 and 33, or 5 and 25) from small to large. highFirst reads 95 82 70.
To send ties from large to small instead, use ThenByDescending: nums.OrderBy(n => n % 10).ThenByDescending(n => n) reads 41 33 13 25 5, so 33 now comes before 13.
Things to know
- Don't call
OrderBytwice. The secondOrderBysorts everything again and forgets the first rule. On the numbers above,nums.OrderBy(n => n % 10).OrderBy(n => n)gives5 13 25 33 41. UseThenByfor the second rule. - LINQ makes a new sequence and leaves the list as it was. End with
ToList()to get aListback. Withwordsholdingpear fig apple,words.OrderBy(w => w.Length).ToList()readsfig pear appleandwordsstill readspear fig apple. - The list's own
Sort()changes the list itself instead.
The lesson's task
A pet shop has toy prices 12, 5, 30 and 8, and pets Rex, Luna, Bella, Max, Bo and Coco. Make highFirst with the prices from high to low, and byLastLetter with the names sorted by their last letter, with names that share a last letter going from A to Z.
- Call
OrderByDescendingonpriceswithp => p: each price is sorted by itself, from the biggest down. ThenToList(). - For the names,
OrderBywith the last letter,n[n.Length - 1]. A string indexed with a number gives achar, and chars sort in alphabetical order. - Add
ThenBy(n => n), so names with the same last letter go from A to Z. Max and Rex both end in x, and this puts Max first. ThenToList().
class Solution {
public void MainFunction() {
List<int> prices = new List<int>(new[] {12, 5, 30, 8});
List<string> names = new List<string>(new[] {"Rex", "Luna", "Bella", "Max", "Bo", "Coco"});
List<int> highFirst = prices.OrderByDescending(p => p).ToList();
foreach (int price in highFirst) {
Console.WriteLine(price);
}
List<string> byLastLetter = names.OrderBy(n => n[n.Length - 1]).ThenBy(n => n).ToList();
foreach (string name in byLastLetter) {
Console.WriteLine(name);
}
}
}
The prices print as 30, 12, 8, 5. The names end in a (Bella, Luna), o (Bo, Coco) and x (Max, Rex), so they print as:
Bella
Luna
Bo
Coco
Max
Rex
Common mistakes
- Two
OrderBycalls. Only the last one counts; chainThenByinstead. - Forgetting
ToList().OrderByreturns a sequence, which can't be assigned to aList<int>variable. - Mixing up the direction.
OrderBygoes small to large;OrderByDescendinggoes large to small. - Expecting the original list to change. Print the new list, not
pricesornames.
Key takeaways
OrderByandOrderByDescendingtake a lambda that picks what to sort by.ThenByandThenByDescendingadd rules that only matter on ties.- LINQ returns a new sequence;
ToList()turns it back into aList.
