# C# sort List

C# sort list tutorial shows how to sort list elements in C# language. C# tutorial is a comprehensive tutorial on C# language.

## Sorting

In computer science, sorting is arranging elements in an ordered sequence. Over the years, several algorithms were developed to perform sorting on data, including merge sort, quick sort, selection sort, or bubble sort. (The other meaning of sorting is categorizing; it is grouping elements with similar properties.)

The opposite of sorting, rearranging a sequence of elements in a random or meaningless order, is called shuffling.

Data can be sorted alphabetically or numerically. The sort key specifies the criteria used to perform the sort. It is possible to sort objects by multiple keys. For instance, when sorting users, the names of the users could be used as primary sort key, and their occupation as the secondary sort key.

Note: In C#, we can sort list elements with the built-in `Sort` method or use LINQ's `OrderBy`.

## Sorting order

A standard order is called the ascending order: a to z, 0 to 9. The reverse order is called the descending order: z to a, 9 to 0. For dates and times, ascending means that earlier values precede later ones e.g. 1/1/2020 will sort ahead of 1/1/2021.

## Stable sort

A stable sort is one where the initial order of equal elements is preserved. Some sorting algorithms are naturally stable, some are unstable. For instance, the merge sort and the bubble sort are stable sorting algorithms. On the other hand, heap sort and quick sort are examples of unstable sorting algorithms.

Consider the following values: `3715593`. A stable sorting produces the following: `1335579`. The ordering of the values 3 and 5 is kept. An unstable sorting may produce the following: `1335579`.

C# internally uses a stable sort algorithm.

## C# List Sort method

The `Sort` method sorts the elements or a portion of the elements in the list.

• Sort(Comparison<T>) - Sorts the elements in the entire List<T> using the specified Comparison<T>.
• Sort(Int32, Int32, IComparer<T>) - Sorts the elements in a range of elements in List<T> using the specified comparer.
• Sort() - Sorts the elements in the entire List<T> using the default comparer.
• Sort(IComparer<T>) - Sorts the elements in the entire List<T> using the specified comparer.

Note: The `Sort` method sorts the list in-place, while the LINQ's `OrderBy` method returns a sorted enumeration of list elements.

## The comparison method

The sorting algorithms are already built into the standard library of the language. If the data is not sorted naturally, we need to provide a comparison method (either a class method or a lambda expression) which tells the underlying sorting algorithm how to sort the data. What attributes to sort and in what way.

```public int CompareTo(Card other)
{
var index = Rank.CompareTo(other.Rank);
if (index == 0) index = Suit.CompareTo(other.Suit);
return index;
}
```

For instance, this comparison class method tells to sort the objects by the `Rank` and if the rank is the same, then by `Suit`. We always compare two elements; in our case, two card objects. The comparison method returns 0 in case the elements are equal, -1 when the first element is less than the second, and 1 when the first element is greater than the second.

Oftentimes, our comparison function calls other comparison functions; in our case, the `Rank` and the `Suit` are enumerations and we compare them by the built-in `CompareTo` method.

## C# List sort integers

The following example sorts integers.

Program.cs
```using System;
using System.Collections.Generic;

var nums = new List<int> { 2, 1, 8, 0, 4, 3, 5, 7, 9 };

nums.Sort();
Console.WriteLine(string.Join(",", nums));

nums.Reverse();
Console.WriteLine(string.Join(",", nums));
```

C# is using a default comparer method to sort integers numerically. The `Sort` method orders the integers in ascending order, while the `Reverse` method in descending order.

```\$ dotnet run
0,1,2,3,4,5,7,8,9
9,8,7,5,4,3,2,1,0
```

This is the output.

The following example sorts integers with LINQ. In LINQ, we can choose between the query syntax or the method syntax.

Program.cs
```using System;
using System.Collections.Generic;
using System.Linq;

var nums = new List<int> { 2, 1, 8, 0, 4, 3, 5, 7, 9 };

var enum1 = from num in nums
orderby num
select num;

foreach (var e in enum1)
{
Console.Write(\$"{e} ");
}

Console.WriteLine();

var enum2 = from num in nums
orderby num descending
select num;

foreach (var e in enum2)
{
Console.Write(\$"{e} ");
}

Console.WriteLine();
```

The example sorts integers in ascending and descending order using LINQ's query syntax.

```\$ dotnet run
0 1 2 3 4 5 7 8 9
9 8 7 5 4 3 2 1 0
```

This is the output.

## C# List sort strings

Like integers, strings are sorted by `Sort` alphabetically by default without any additional effort.

Program.cs
```using System;
using System.Collections.Generic;

var words = new List<string> {"falcon", "order", "war",
"sky", "ocean", "blue", "cloud", "boy"};

words.Sort();
Console.WriteLine(string.Join(",", words));

words.Reverse();
Console.WriteLine(string.Join(",", words));
```

The example sorts strings in ascending and descending order.

```\$ dotnet run
blue,boy,cloud,falcon,ocean,order,sky,war
war,sky,order,ocean,falcon,cloud,boy,blue
```

This is the output.

## C# List sort accented strings

In order to sort accented strings, we need to provide the appropriate `CultureInfo`.

Program.cs
```using System;
using System.Globalization;
using System.Collections.Generic;

Console.OutputEncoding = System.Text.Encoding.UTF8;

var words = new List<string> { "čaj", "auto", "drevo", "cibuľa",
"čučoriedka", "banán", "čerešňa", "červený", "čierny", "cesnak" };

words.Sort();

foreach (var word in words)
{
Console.WriteLine(word);
}
```

The example sorts Slovak words. Slovak language has many accented characters such as č or ň.

```\$ dotnet run
auto
banán
cesnak
cibuľa
čaj
čerešňa
červený
čierny
čučoriedka
drevo
```

The words are sorted correctly according to the Slovak norm.

## C# List sort by string length

The following example sorts the list of words by the words' length.

Program.cs
```using System;
using System.Collections.Generic;

var words = new List<string> {"falcon", "order", "war",
"sky", "ocean", "blue", "cloud", "boy", "by", "raven",
"station", "batallion"};

words.Sort((a, b) => a.Length.CompareTo(b.Length));
Console.WriteLine(string.Join(",", words));

words.Sort((a, b) => b.Length.CompareTo(a.Length));
Console.WriteLine(string.Join(",", words));
```

We need to provide our own comparison method to do the job.

```words.Sort((a, b) => a.Length.CompareTo(b.Length));
Console.WriteLine(string.Join(",", words));
```

We provide an anonymous method to the `Sort` method. This method uses the `CompareTo` method of the integer type to compare the two values. The length of the words is returned with the `Length` property.

```\$ dotnet run
by,war,sky,boy,blue,order,ocean,cloud,raven,falcon,station,batallion
batallion,station,falcon,order,ocean,cloud,raven,blue,war,sky,boy,by
```

This is the output.

The following example does the same thing with LINQ.

Program.cs
```using System;
using System.Collections.Generic;
using System.Linq;

var words = new List<string> {"falcon", "order", "war",
"sky", "ocean", "blue", "cloud", "boy", "by", "raven",
"station", "batallion"};

var res = from word in words
orderby word.Length
ascending
select word;

foreach (var word in res)
{
Console.WriteLine(word);
}

var res2 = from word in words
orderby word.Length
descending
select word;

foreach (var word in res2)
{
Console.WriteLine(word);
}
```

In the example, we sort the words by their length in asceding and descending order using LINQ query expressions.

## C# List sort names by surname

When we want to sort names by their surname, assuming that the whole name is a single string, we need to provide a custom comparison method.

Program.cs
```using System;
using System.Collections.Generic;

var names = new List<string> {"John Doe", "Lucy Smith",
"Benjamin Young", "Robert Brown", "Thomas Moore",
"Linda Black", "Adam Smith", "Jane Smith"};

names.Sort((n1, n2) => n1.Split(" ").CompareTo(n2.Split(" ")));
Console.WriteLine(string.Join(",", names));
```

To solve this, we split the string into two parts and compare the second part of the string in a lambda expression.

```\$ dotnet run
Linda Black
Robert Brown
John Doe
Thomas Moore
Lucy Smith
Jane Smith
Benjamin Young
```

This is the output. Note that the order of the Smiths is kept; this is an example of a stable sorting algorithm.

The following example provides a LINQ solution.

Program.cs
```using System;
using System.Collections.Generic;
using System.Linq;

var names = new List<string> {"John Doe", "Lucy Smith",
"Benjamin Young", "Robert Brown", "Thomas Moore",
"Linda Black", "Adam Smith", "Jane Smith"};

var res = from name in names
orderby name.Split(" ")
ascending
select name;

foreach (var name in res)
{
Console.WriteLine(name);
}
```

The example sorts the names by their surname using LINQ query expression syntax.

## C# List sort case insensitive

To compare strings in a case insentitive manner, we can use the built-in `StringComparer.OrdinalIgnoreCase`.

Program.cs
```using System;
using System.Collections.Generic;

var words = new List<string>
{
"world", "War", "abbot", "Caesar", "castle", "sky", "den",
"forest", "ocean", "water", "falcon", "owl", "rain", "Earth"
};

words.Sort(StringComparer.OrdinalIgnoreCase);
words.ForEach(w => Console.WriteLine(w));
```

The example sorts a list of words in case insensitive order.

```\$ dotnet run
abbot
Caesar
castle
den
Earth
falcon
forest
ocean
owl
rain
sky
War
water
world
```

This is the output.

## C# List sort tuples

The following example sorts a list of tuples.

Program.cs
```using System;
using System.Collections.Generic;

var data = new List<(string Name, int Grade)>
{
("Patrick", 89),
("Lucia", 92),
("Veronika", 72),
("Robert", 78),
("Maria", 65),
("Andrea", 51),
("Ondrej", 45)
};

Console.WriteLine(string.Join(", ", data));

Console.WriteLine(string.Join(", ", data));
```

In the example, we have a list of tuples representing students and their grades. We sort the tuples by grade in ascending and descending order.

```\$ dotnet run
(Ondrej, 45), (Andrea, 51), (Maria, 65), (Veronika, 72), (Robert, 78), ...
(Lucia, 92), (Patrick, 89), (Robert, 78), (Veronika, 72), (Maria, 65), ...
```

This is the output.

## C# List sort objects

In the following example, we sort a list of `User` objects.

Program.cs
```using System;
using System.Collections.Generic;

var users = new List<User>();

users.Sort((u1, u2) => u1.LastName.CompareTo(u2.LastName));
users.ForEach(user => Console.WriteLine(user));

record User(string FirstName, string LastName, int Salary);
```

We have a list of user objects. The user has three attributes: first name, last name, and salary. We sort the list by users' last names.

```users.Sort((u1, u2) => u1.LastName.CompareTo(u2.LastName));
```

In the lambda expression, we compare the `LastName` property of the two elements.

```\$ dotnet run
User { FirstName = Robin, LastName = Brown, Salary = 2300 }
User { FirstName = John, LastName = Doe, Salary = 1230 }
User { FirstName = John, LastName = Doe, Salary = 1230 }
User { FirstName = Janet, LastName = Doe, Salary = 980 }
User { FirstName = Joe, LastName = Draker, Salary = 1190 }
User { FirstName = Lucy, LastName = Novak, Salary = 670 }
User { FirstName = Ben, LastName = Walter, Salary = 2050 }
```

This is the output.

Program.cs
```using System;
using System.Linq;
using System.Collections.Generic;

var users = new List<User>();

Console.WriteLine("sort ascending by salary");

var enum1 = from user in users
orderby user.Salary
select user;

foreach (var e in enum1)
{
Console.WriteLine(e);
}

Console.WriteLine("--------------------------");

Console.WriteLine("sort descending by salary");

var enum2 = from user in users
orderby user.Salary descending
select user;

foreach (var e in enum2)
{
Console.WriteLine(e);
}

record User(string FirstName, string LastName, int Salary);
```

The example sorts a list of user objects by users' salaries. It uses the LINQ query syntax.

```\$ dotnet run
sort ascending by salary
User { FirstName = Lucy, LastName = Novak, Salary = 670 }
User { FirstName = Janet, LastName = Doe, Salary = 980 }
User { FirstName = Joe, LastName = Draker, Salary = 1190 }
User { FirstName = John, LastName = Doe, Salary = 1230 }
User { FirstName = Ben, LastName = Walter, Salary = 2050 }
User { FirstName = Robin, LastName = Brown, Salary = 2300 }
--------------------------
sort descending by salary
User { FirstName = Robin, LastName = Brown, Salary = 2300 }
User { FirstName = Ben, LastName = Walter, Salary = 2050 }
User { FirstName = John, LastName = Doe, Salary = 1230 }
User { FirstName = Joe, LastName = Draker, Salary = 1190 }
User { FirstName = Janet, LastName = Doe, Salary = 980 }
User { FirstName = Lucy, LastName = Novak, Salary = 670 }
```

This is the output.

## C# List sort DateTime

In the following example, we sort a list of users by their birthdays.

Program.cs
```using System;
using System.Linq;
using System.Collections.Generic;

var users = new List<User>();
users.Add(new User("John", "Doe", new DateTime(1983, 9, 4)));
users.Add(new User("Lucy", "Novak", new DateTime(1978, 11, 18)));
users.Add(new User("Ben", "Walter", new DateTime(1998, 12, 1)));
users.Add(new User("Robin", "Brown", new DateTime(2001, 2, 14)));
users.Add(new User("Joe", "Draker", new DateTime(1980, 1, 10)));
users.Add(new User("Janet", "Doe", new DateTime(1967, 8, 23)));

Console.WriteLine("sort ascending by birthday");
users.Sort((u1, u2) => DateTime.Compare(u1.Birthday, u2.Birthday));
users.ForEach(u => Console.WriteLine(u));

Console.WriteLine("--------------------------");
Console.WriteLine("sort descending by birthday");

var enum1 = users.OrderByDescending(e => e.Birthday);
foreach (var u in enum1)
{
Console.WriteLine(u);
}

Console.WriteLine("--------------------------");
Console.WriteLine("sort ascending by birthday");

var enum2 = from user in users
orderby user.Birthday
select user;

foreach (var u in enum2)
{
Console.WriteLine(u);
}

record User(string FirstName, string LastName, DateTime Birthday);
```

In the example, we sort the list of user objects by their birthdays using the `Sort` method, and using LINQ query syntax and method syntax.

```\$ dotnet run
sort ascending by birthday
User { FirstName = Janet, LastName = Doe, Birthday = 8/23/1967 12:00:00 AM }
User { FirstName = Lucy, LastName = Novak, Birthday = 11/18/1978 12:00:00 AM }
User { FirstName = Joe, LastName = Draker, Birthday = 1/10/1980 12:00:00 AM }
User { FirstName = John, LastName = Doe, Birthday = 9/4/1983 12:00:00 AM }
User { FirstName = Ben, LastName = Walter, Birthday = 12/1/1998 12:00:00 AM }
User { FirstName = Robin, LastName = Brown, Birthday = 2/14/2001 12:00:00 AM }
--------------------------
sort descending by birthday
User { FirstName = Robin, LastName = Brown, Birthday = 2/14/2001 12:00:00 AM }
User { FirstName = Ben, LastName = Walter, Birthday = 12/1/1998 12:00:00 AM }
User { FirstName = John, LastName = Doe, Birthday = 9/4/1983 12:00:00 AM }
User { FirstName = Joe, LastName = Draker, Birthday = 1/10/1980 12:00:00 AM }
User { FirstName = Lucy, LastName = Novak, Birthday = 11/18/1978 12:00:00 AM }
User { FirstName = Janet, LastName = Doe, Birthday = 8/23/1967 12:00:00 AM }
--------------------------
sort ascending by birthday
User { FirstName = Janet, LastName = Doe, Birthday = 8/23/1967 12:00:00 AM }
User { FirstName = Lucy, LastName = Novak, Birthday = 11/18/1978 12:00:00 AM }
User { FirstName = Joe, LastName = Draker, Birthday = 1/10/1980 12:00:00 AM }
User { FirstName = John, LastName = Doe, Birthday = 9/4/1983 12:00:00 AM }
User { FirstName = Ben, LastName = Walter, Birthday = 12/1/1998 12:00:00 AM }
User { FirstName = Robin, LastName = Brown, Birthday = 2/14/2001 12:00:00 AM }
```

This is the output.

## C# List sort objects by multiple fields

The following example sorts user objects by multiple fields.

Program.cs
```using System;
using System.Collections.Generic;

var users = new List<User>();

users.Sort((u1, u2) =>
{
int result = u1.LastName.CompareTo(u2.LastName);
return result == 0 ? u1.Salary.CompareTo(u2.Salary) : result;
});

Console.WriteLine("sort ascending by last name and salary");

foreach (var user in users)
{
Console.WriteLine(user);
}

record User(string FirstName, string LastName, int Salary);
```

In the example, we sort users first by last names and then by salaries.

```users.Sort((u1, u2) =>
{
int result = u1.LastName.CompareTo(u2.LastName);
return result == 0 ? u1.Salary.CompareTo(u2.Salary) : result;
});
```

First, the users are compared by their `LastName` property. If the comparison returns 0, that is their last names are equal, we compare their salaries.

```\$ dotnet run
sort ascending by last name and salary
User { FirstName = Robin, LastName = Brown, Salary = 2300 }
User { FirstName = Janet, LastName = Doe, Salary = 980 }
User { FirstName = John, LastName = Doe, Salary = 1230 }
User { FirstName = Amy, LastName = Doe, Salary = 1250 }
User { FirstName = Joe, LastName = Draker, Salary = 1190 }
User { FirstName = Lucy, LastName = Novak, Salary = 670 }
User { FirstName = Albert, LastName = Novak, Salary = 1930 }
User { FirstName = Ben, LastName = Walter, Salary = 2050 }
```

This is the output.

The next example sorts by multiple fields with LINQ methods.

Program.cs
```using System;
using System.Linq;
using System.Collections.Generic;

var users = new List<User>();

Console.WriteLine("sort ascending by last name and salary");

var enum1 = users.OrderBy(u => u.LastName).ThenBy(u => u.Salary);
foreach (var user in enum1)
{
Console.WriteLine(user);
}

record User(string FirstName, string LastName, int Salary);
```

The users are sorted with `OrderBy` and `ThenBy` methods.

## C# List sort by rating

Image that we have a rating system which cannot be sorted alphabetically. For instance, rating can have values such as C, C+, C-. One solution is to use enumerations.

Program.cs
```using System;
using System.Collections.Generic;

var products = new List<Product>();
products.Add(new Product() { Name = "Product A", ProdRat = Rating.A });
products.Add(new Product() { Name = "Product B", ProdRat = Rating.AMinus });
products.Add(new Product() { Name = "Product C", ProdRat = Rating.B });
products.Add(new Product() { Name = "Product D", ProdRat = Rating.APlus });
products.Add(new Product() { Name = "Product E", ProdRat = Rating.D });
products.Add(new Product() { Name = "Product F", ProdRat = Rating.C });
products.Add(new Product() { Name = "Product G", ProdRat = Rating.CMinus });
products.Add(new Product() { Name = "Product G", ProdRat = Rating.CPlus });

Console.WriteLine("sorted by rating ascending");
products.Sort((p1, p2) => p1.ProdRat.CompareTo(p2.ProdRat));

foreach (var product in products)
{
Console.WriteLine(product);
}

Console.WriteLine("---------------------");

Console.WriteLine("sorted by rating descending");
products.Sort((p1, p2) => p2.ProdRat.CompareTo(p1.ProdRat));

foreach (var product in products)
{
Console.WriteLine(product);
}

enum Rating
{
D,
DPlus,
CMinus,
C,
CPlus,
B,
BPlus,
BMinus,
AMinus,
A,
APlus
}

class Product
{
private Dictionary<Rating, string> ratings = new Dictionary<Rating, string>
{
{Rating.APlus, "A+"}, {Rating.A, "A"}, {Rating.AMinus, "A-"},
{Rating.BPlus, "B+"}, {Rating.B, "B"}, {Rating.BMinus, "B-"},
{Rating.CPlus, "C+"}, {Rating.C, "C"}, {Rating.CMinus, "C-"},
{Rating.DPlus, "D+"}, {Rating.D, "D"}
};

public string Name { get; init; }
public Rating ProdRat { get; init; }

public override string ToString()
{
return \$"{this.Name} has rating {this.ratings[this.ProdRat]}";
}
}
```

In the example, we sort products by their ratings.

```products.Sort((p1, p2) => p1.ProdRat.CompareTo(p2.ProdRat));
```

In the lambda expression, we compare the product ranking enumerations with `CompareTo`.

```enum Rating
{
D,
DPlus,
CMinus,
C,
CPlus,
B,
BPlus,
BMinus,
AMinus,
A,
APlus
}
```

We have an enumeration of ratings. Internally, the values are given integer numbers where Rating.D has the lowest value and Rating.APlus the highest.

```private Dictionary<Rating, string> ratings = new Dictionary<Rating, string>
{
{Rating.APlus, "A+"}, {Rating.A, "A"}, {Rating.AMinus, "A-"},
{Rating.BPlus, "B+"}, {Rating.B, "B"}, {Rating.BMinus, "B-"},
{Rating.CPlus, "C+"}, {Rating.C, "C"}, {Rating.CMinus, "C-"},
{Rating.DPlus, "D+"}, {Rating.D, "D"}
};
```

In this dictionary, we assign string representations to our ranking enums.

```\$ dotnet run
sorted by rating ascending
Product E has rating D
Product G has rating C-
Product F has rating C
Product G has rating C+
Product C has rating B
Product B has rating A-
Product A has rating A
Product D has rating A+
---------------------
sorted by rating descending
Product D has rating A+
Product A has rating A
Product B has rating A-
Product C has rating B
Product G has rating C+
Product F has rating C
Product G has rating C-
Product E has rating D
```

The products are sorted by their ratings in ascending and descending orders.

## C# List sort cards

In the next example, we sort cards. The `Card` object implements the `IComparable` iterface. The interface is used in cases where natural ordering of objects is possible.

In Poker and similar card games, the card value is determined by its rank. And if needed, by its suit. There is only one possible way of sorting cards in Poker; therefore, we can use the `IComparable` interface.

Program.cs
```using System;
using System.Collections.Generic;

var cards = new List<Card>
{
new Card(Rank.King, Suit.Diamonds),
new Card(Rank.Five, Suit.Hearts),
new Card(Rank.Ace, Suit.Clubs),
new Card(Rank.Jack, Suit.Diamonds)
};

cards.Sort();

foreach (var card in cards)
{
Console.WriteLine(card);
}

enum Rank
{
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace
}

enum Suit
{
Clubs,
Diamonds,
Hearts,
}

class Card : IComparable<Card>
{
private Rank Rank { get; set; }
private Suit Suit { get; set; }

public Card(Rank rank, Suit suit)
{
Rank = rank;
Suit = suit;
}

public int CompareTo(Card other)
{
var index = Rank.CompareTo(other.Rank);
if (index == 0) index = Suit.CompareTo(other.Suit);
return index;
}

public override string ToString()
{
return \$"{Rank} of {Suit}";
}
}
```

In the example, we sort cards.

```class Card : IComparable<Card>
```

The `Card` implements the `IComparable` interface. This forces us to implement its `CompareTo` method.

```public int CompareTo(Card other)
{
var index = Rank.CompareTo(other.Rank);
if (index == 0) index = Suit.CompareTo(other.Suit);
return index;
}
```

In the `CompareTo` method, we first compare the rank of the card. If the rank is the same, we compare the suit.

```var cards = new List<Card>
{
new Card(Rank.King, Suit.Diamonds),
new Card(Rank.Five, Suit.Hearts),
new Card(Rank.Ace, Suit.Clubs),
new Card(Rank.Jack, Suit.Diamonds)
};
```

We have a list of six cards that we want to sort.

```cards.Sort();
```

Without any parameters, the `Sort` method calls the built-in `CompareTo` to sort the data.

```\$ dotnet run
Five of Hearts