Changes in the C# language allow us to write more concise code than ever before, and it’s fun to see what solutions developers write. In this short but fun post, I’ll be writing a method that takes in an `int` and converts it into its ordinal position, the kind of output you might see on a leaderboard. So, for example, the value of `1` would be `1st`, the value of `2` is `2nd`, and so on.

# The Ranking Problem

Given we have a collection of integers, we want to convert those values into their human-readable ordinal values. In English, we describe position using the suffixes of `st`, `nd`, `rd`, and `th`. So, for example, a collection of integers containing the values of `1, 2, 3, 4` would be equivalent to `1st, 2nd, 3rd, 4th`. There are a few rules to keep in mind when dealing with numbers and their possible suffixes:

1. When a value of `1` is in the position of the one whole number part, it will have a suffix of `st` unless the value in the tens whole-number part is `11`; in that case, the suffix is `th`.
2. When a value of `2` is in the position of the one whole number part, it will have a suffix of `nd` unless the value in the tens whole-number part is `12`; in that case, the suffix is `th`.
3. When a value of `3` is in the position of the one whole number part, it will have a suffix of `rd` unless the value in the tens whole-number part is `13`; in that case, the suffix is `th`.
4. In all other scenarios, the suffix will be `th`.

In general, the only numbers we should be cautious about are the ones that end in `1`, `2`, `3`, `11`, `12`, and `13`. We may treat all other numbers the same with the `th` suffix.

Let’s write some code.

## Using Pattern Matching For Pretty Output

Given our rules, we can use C#’s pattern matching to define our rules around a provided `int` value. Our first step is to get the whole number part of our integer, and we can do that by using the remainder operator.

``````var ones = value % 10;
var tens = value % 100;
``````

Now that we know the whole-number parts of our integer value, we can write our pattern matching switch statement.

``````var suffix = ones switch {
1 when tens != 11 => "st",
2 when tens != 12 => "nd",
3 when tens != 13 => "rd",
_ => "th"
};
``````

Now, let’s put it all together. The method should be straightforward to implement from here.

``````string Ranking(int value)
{
var ones = value % 10;
var tens = value % 100;

var suffix = ones switch {
1 when tens != 11 => "st",
2 when tens != 12 => "nd",
3 when tens != 13 => "rd",
_ => "th"
};

return string.Concat(value.ToString("N0"), suffix);
}
``````

I end up using the string formatter of `N0` to format the integer with zero (0) decimal placeholders. Let’s run the method in a console application.

``````using static System.Console;
using static System.String;

string Ranking(int value)
{
var ones = value % 10;
var tens = value % 100;

var suffix = ones switch {
1 when tens != 11 => "st",
2 when tens != 12 => "nd",
3 when tens != 13 => "rd",
_ => "th"
};

return Concat(value.ToString("N0"), suffix);
}

var low = new List<int> { 1, 2, 3, 4, 11 }.Select(Ranking);
var high = new[] {1_001, 1_002, 1_003, 1_004, 1_011 }.Select(Ranking);

WriteLine(\$"First collection: {Join(", ", low) }");
WriteLine(\$"Second collection: {Join(", ", high)}");
``````

Writing the app, we get the following application output.

``````First collection: 1st, 2nd, 3rd, 4th, 11th
Second collection: 1,001st, 1,002nd, 1,003rd, 1,004th, 1,011th
``````

Neat! I hope you enjoyed this short post about C# pattern matching, and let me know if you think you could improve it by reaching me on Twitter @buhakmeh. Thanks for reading my posts and sharing them with friends and colleagues.