Skip to content

/commands/csharp/sort-list-by-property-linq

c# sort a list of objects by property (OrderBy, ThenBy, List.Sort)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 10.0.401updated
tool
C#
versions
.NET Framework 3.5+ (LINQ), Order(): .NET 7+
os
any

list.OrderBy(p => p.Age) sorts a list of objects by a property with LINQ and returns a new sequence; add .ToList() to get a List<T>. Use OrderByDescending for the reverse order and ThenBy/ThenByDescending for a second key. To sort the existing list in place, call list.Sort((a, b) => a.Age.CompareTo(b.Age)).

Examples

bash
cat > sort.cs <<'EOF'
List<Person> people =
[
    new("zoe", 31, "ops"),
    new("adam", 25, "dev"),
    new("Bea", 31, "dev"),
    new("Carl", 19, "ops"),
];
static string Names(IEnumerable<Person> ps) => string.Join(", ", ps.Select(p => p.Name));

Console.WriteLine("by age:          " + Names(people.OrderBy(p => p.Age)));
Console.WriteLine("by age desc:     " + Names(people.OrderByDescending(p => p.Age)));
Console.WriteLine("team, then name: " + Names(people.OrderBy(p => p.Team).ThenBy(p => p.Name)));
Console.WriteLine("ordinal name:    " + Names(people.OrderBy(p => p.Name, StringComparer.Ordinal)));
Console.WriteLine("ignore case:     " + Names(people.OrderBy(p => p.Name, StringComparer.OrdinalIgnoreCase)));
Console.WriteLine("list unchanged:  " + Names(people));

people.Sort((a, b) => a.Age.CompareTo(b.Age));
Console.WriteLine("after Sort():    " + Names(people));

record Person(string Name, int Age, string Team);
EOF
dotnet run sort.cs

Output

by age:          Carl, adam, zoe, Bea
by age desc:     zoe, Bea, adam, Carl
team, then name: adam, Bea, Carl, zoe
ordinal name:    Bea, Carl, adam, zoe
ignore case:     adam, Bea, Carl, zoe
list unchanged:  zoe, adam, Bea, Carl
after Sort():    Carl, adam, zoe, Bea

OrderBy keeps zoe before Bea when both are 31, because it is stable. The ordinal comparer sorts by character code, so capitalised names come before adam; OrdinalIgnoreCase gives alphabetical order regardless of case. Only Sort() changes people itself.

Options

CodeResult
list.OrderBy(x => x.Key).ToList()New list sorted ascending
list.OrderByDescending(x => x.Key)Descending
.OrderBy(x => x.A).ThenBy(x => x.B)Sort by A, then by B for equal A values
.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase)Case-insensitive string order
list.Sort((a, b) => a.Key.CompareTo(b.Key))In place, not stable
numbers.Order() / OrderDescending()Sort the elements themselves (.NET 7+)
from p in people orderby p.Age descending select pQuery syntax, same as OrderByDescending

Pitfalls

  • Discarded result. people.OrderBy(p => p.Age); on its own line does nothing visible: the sorted sequence is thrown away. Assign it, or use Sort.
  • OrderBy twice. .OrderBy(a).OrderBy(b) sorts by b only (stably, so a survives as a tie-breaker by accident). Use ThenBy for secondary keys.
  • Null keys sort first in ascending order with the default comparer; a null element itself causes a NullReferenceException inside the key selector.
  • Missing LINQ. Without implicit usings, OrderBy needs using System.Linq;; otherwise the compiler reports CS1061 does not contain a definition for OrderBy.
  • Record or class? Sorting works the same for both; see record vs class for which to use for data like this.

Confirm it worked

Print the key you sorted by next to each item and check the first and last values, as in the example. For a sorted list, list.Zip(list.Skip(1)).All(t => t.First.Age <= t.Second.Age) returns true.

FAQ

Does OrderBy change the original list?

No. OrderBy returns a new, lazily evaluated sequence; the list keeps its order. Call ToList() to store the result, or use List.Sort to sort in place.

Is OrderBy stable?

Yes. The documentation states that OrderBy performs a stable sort: elements with equal keys keep their original order. List.Sort is not stable.

How do I sort strings case-insensitively?

Pass a comparer: people.OrderBy(p => p.Name, StringComparer.OrdinalIgnoreCase). For culture-aware ordering use StringComparer.CurrentCultureIgnoreCase or a specific CultureInfo.

Sources