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:
- When a value of
1
is in the position of the one whole number part, it will have a suffix ofst
unless the value in the tens whole-number part is11
; in that case, the suffix isth
. - When a value of
2
is in the position of the one whole number part, it will have a suffix ofnd
unless the value in the tens whole-number part is12
; in that case, the suffix isth
. - When a value of
3
is in the position of the one whole number part, it will have a suffix ofrd
unless the value in the tens whole-number part is13
; in that case, the suffix isth
. - 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.