# Convert an array of numbers to an array of ordinal numbers in JS

## How to implement first, second, third, and nth in JavaScript? We discuss that in depth in this article.

By: Ajdin Imsirovic 14 January 2021

This exercise is kind of fun. For any given array of numbers, we want to return an array of ordinal numbers. For example, given an array of `[ 1, 2, 3 ]`

, we want to return `[ '1st', '2nd', '3rd' ]`

.

How do we do this?

As anything else, there are always a number of approaches:

- Use a look-up array
- Convert the number into an array, then check the last member
- Use the built-in
`Intl`

object

Let’s start with the look-up array solution. We’ll start with an array consisting of three members:

1
2

const sourceArray = [1,2,3];
const lookupArray = ['st', 'nd', 'rd', 'th'];

Now, we’ll run the `Array.prototype.map()`

function on our array of numbers, to return their ordinal counterparts:

1
2
3

const sourceArray = [1,2,3];
const lookupArray = ['st', 'nd', 'rd', 'th'];
sourceArray.map(member => member + lookupArray[member])

The above will return:

Our code works, but we have an off-by-1 logical error in our code. In other words, instead of the given result, we need this array returned:

This is an easy fix:

1
2
3
4

var arr = [1,2,3];
var lookup = ['st','nd','rd','th'];
arr.map(member => member + lookup[member-1])
// (3) ["1st", "2nd", "3rd"]

Now we’re getting back the expected result. What we can conclude from the look-up array approach is that it will work great for smaller arrays of numbers. It’s a quick and easy solution when we need to convert a short array of numbers to its ordinal counterpart. However, how do we deal with longer arrays of numbers? What do we do if our array’s length is a lot larger, say, in the hundreds? For that we’ll use the second solution.

The second solution is *Convert the number into an array, then check the last member*. Let’s start from the core of this solution: instead of working on an array of numbers, we’ll work with a single number. So:

1
2
3
4
5
6
7

function addOrdinalSuffix(num) {
console.log(num + 'th');
}
let userPickedNum = prompt('Type a number');
addOrdinalSuffix(userPickedNum);

The above code works perfectly for a majority of cases. But what if a user types, for example, `4321`

? This is the output:

This is obviously not the correct solution; it should have been `4321st`

. So let’s take the number `4321`

and convert it into an array:

Why are we getting the above error? Because the single dot after `4321`

stands for *the decimal delimiter*. Luckily, the fix here is really easy:

Great, now we’re successfully splitting our number into an array of characters. Next, let’s log out only the last member of the array (i.e the last digit of our number):

1
2
3
4
5
6
7
8
9
10

function addOrdinalSuffix(num) {
let arr = num.toString().split('');
console.log(arr);
// console.log(num + 'th');
}
let userPickedNum = prompt('Type a number');
addOrdinalSuffix(userPickedNum);
// returns: (4) ["4", "3", "2", "1"]

Now let’s log out only the last member of the array, using:

Here’s the full updated code:

1
2
3
4
5
6
7
8
9
10

function addOrdinalSuffix(num) {
let arr = num.toString().split('');
console.log(arr[arr.length - 1]);
// console.log(num + 'th');
}
let userPickedNum = prompt('Type a number');
addOrdinalSuffix(userPickedNum);
// returns: 1

Now all we need to do is map the suffixes like this:

- if we get a
`1`

, we return`1st`

- if we get a
`2`

, we return`2nd`

- if we get a
`3`

, we return`3rd`

Here’s the updated code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

function addOrdinalSuffix(num) {
let arr = num.toString().split('');
let arrLastMember = arr[arr.length - 1];
let suffix = 'th';
if (arrLastMember == 1) {
suffix = 'st';
}
if (arrLastMember == 2) {
suffix = 'nd';
}
if (arrLastMember == 3) {
suffix = 'rd';
}
console.log(num + suffix);
}
let userPickedNum = prompt('Type a number');
addOrdinalSuffix(userPickedNum);
// returns: 4321st

At this point, our task is seemingly finished, but there’s a weird edge case with teens. If we ran the above code and passed, for example, number `11`

to the prompt, we’d get back: `11st`

. This is wrong; we should have returned `11th`

.

The solution for this is to check the last two digits instead of one. Then, if the last two digits are `11`

, `12`

, or `13`

, we’ll return a `th`

suffix, and for all other cases, we’ll return the appropriate `st`

, `nd`

, or `rd`

.

Here’s the natural update to our code. Note: this code can be refactored; for now, let’s just think about the logic and not focus too much on optimizing our code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

function addOrdinalSuffix(num) {
let arr = num.toString().split('');
let arrLastMember = arr[arr.length - 1];
let arrSecondLastMember = arr[arr.length - 2];
let suffix = 'th';
console.log('Type is:',
typeof arrSecondLastMember.concat(arrLastMember)
// returns: "type is: string"
);
console.log('The last two digits are:',
arrSecondLastMember.concat(arrLastMember)
);
if (arrLastMember == 1 &&
arrSecondLastMember.concat(arrLastMember) != "11") {
suffix = 'st';
}
if (arrLastMember == 2 &&
arrSecondLastMember.concat(arrLastMember) != "12") {
suffix = 'nd';
}
if (arrLastMember == 3 &&
arrSecondLastMember.concat(arrLastMember) != "13") {
suffix = 'rd';
}
console.log(num + suffix);
}
let userPickedNum = prompt('Type a number');
addOrdinalSuffix(userPickedNum);

Great, our code works fully, and also takes care of edge cases!

To confirm that that is really the case, we could test our improved code by passing random numbers on each function call: `4311`

, `4312`

, `4313`

, `4321`

, `101`

, `111`

, `1001`

, `1011`

, `1515`

.

However, there’s even a better way to do it. We’ll simply write some code to run our `addOrdinalSuffix()`

function on an array of numbers. Here’s the updated code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

function addOrdinalSuffix(num) {
let arr = num.toString().split('');
let arrLastMember = arr[arr.length - 1];
let arrSecondLastMember = arr[arr.length - 2];
let suffix = 'th';
console.log('Type is:',
typeof arrSecondLastMember.concat(arrLastMember)
// returns: "type is: string"
);
console.log('The last two digits are:',
arrSecondLastMember.concat(arrLastMember)
);
if (arrLastMember == 1 &&
arrSecondLastMember.concat(arrLastMember) != "11") {
suffix = 'st';
}
if (arrLastMember == 2 &&
arrSecondLastMember.concat(arrLastMember) != "12") {
suffix = 'nd';
}
if (arrLastMember == 3 &&
arrSecondLastMember.concat(arrLastMember) != "13") {
suffix = 'rd';
}
console.log(num + suffix);
}
let arrayOfNumbers = [
`4311`,
`4312`,
`4313`,
`4321`,
`101`,
`111`,
`1001`,
`1011`,
`1515`
];
arrayOfNumbers.forEach(member => {
console.log('Number:', member);
addOrdinalSuffix(member);
}
);

Here’s the output of the above code:

Note:

This exercise comes from Book 3
of my book series on JS, available on Leanpub.com.