Is there a built-in way to convert an integer into its ordinal string representation (as per this page). That is, something akin to
{1 -> "1st", 2 -> "2nd", (*etc...*)}
or
{1 -> "First", 2 -> "Second", (*etc...*)}
Is there a built-in way to convert an integer into its ordinal string representation (as per this page). That is, something akin to
{1 -> "1st", 2 -> "2nd", (*etc...*)}
or
{1 -> "First", 2 -> "Second", (*etc...*)}
The coolest way is to check the answer to this question by David Carraher. I am shamelessly stealing his code here to write a function that gives you rules for up to maxNumber
:
ordinalRule[maxNumber_Integer] /; maxNumber > 0 :=
Block[{p},
Thread[
Function[{x},
x -> StringSplit[SpokenString[p[[#]]]][[2]] &[x] // Quiet] /@ Range[maxNumber]
]];
For example:
ordinalRule[100]
(*out*){1 -> "1st", 2 -> "2nd", 3 -> "3rd", 4 -> "4th", 5 -> "5th",
6 -> "6th", 7 -> "7th", 8 -> "8th", 9 -> "9th", 10 -> "10th",
11 -> "11th", 12 -> "12th", 13 -> "13th", 14 -> "14th", 15 -> "15th",
16 -> "16th", 17 -> "17th", 18 -> "18th", 19 -> "19th",
20 -> "20th", 21 -> "21st", 22 -> "22nd", 23 -> "23rd", 24 -> "24th",
25 -> "25th", 26 -> "26th", 27 -> "27th", 28 -> "28th",
29 -> "29th", 30 -> "30th", 31 -> "31st", 32 -> "32nd", 33 -> "33rd",
34 -> "34th", 35 -> "35th", 36 -> "36th", 37 -> "37th",
38 -> "38th", 39 -> "39th", 40 -> "40th", 41 -> "41st", 42 -> "42nd",
43 -> "43rd", 44 -> "44th", 45 -> "45th", 46 -> "46th",
47 -> "47th", 48 -> "48th", 49 -> "49th", 50 -> "50th", 51 -> "51st",
52 -> "52nd", 53 -> "53rd", 54 -> "54th", 55 -> "55th",
56 -> "56th", 57 -> "57th", 58 -> "58th", 59 -> "59th", 60 -> "60th",
61 -> "61st", 62 -> "62nd", 63 -> "63rd", 64 -> "64th",
65 -> "65th", 66 -> "66th", 67 -> "67th", 68 -> "68th", 69 -> "69th",
70 -> "70th", 71 -> "71st", 72 -> "72nd", 73 -> "73rd",
74 -> "74th", 75 -> "75th", 76 -> "76th", 77 -> "77th", 78 -> "78th",
79 -> "79th", 80 -> "80th", 81 -> "81st", 82 -> "82nd",
83 -> "83rd", 84 -> "84th", 85 -> "85th", 86 -> "86th", 87 -> "87th",
88 -> "88th", 89 -> "89th", 90 -> "90th", 91 -> "91st",
92 -> "92nd", 93 -> "93rd", 94 -> "94th", 95 -> "95th", 96 -> "96th",
97 -> "97th", 98 -> "98th", 99 -> "99th", 100 -> "100th"}
I don't know whether this counts as built-in though.
----EDIT----
From @Wreach's comment: there is an undocumented built-in (that SpokenString
calls when dealing with numbers to ordinals) that does exactly that:
Speak["stackexchange"];
SpokenStringDump`SpeakOrdinal[121]
(*out*) 121st
In v10 I need to call Speak
before the relevant function auto-loads.
SpokenStringDump`SpeakOrdinal[1]
returning "1st"
. You might have to reference the symbol Speak
first to make sure that the package is auto-loaded.
$\endgroup$
I noticed only afterwards that you were asking for a built-in method. I'm not certain if you would actually want to rely on an undocumented feature instead of writing your own, since it's not hard.
This requires v10 for StringTemplate
. It could be replaced with something else, of course...
Range[120] /.
{ tens_Integer /; Floor[Mod[tens, 100], 10] == 10 :> StringTemplate["`1`th"][tens],
firsts_Integer /; Mod[firsts, 10] == 1 :> StringTemplate["`1`st"][firsts],
seconds_Integer /; Mod[seconds, 10] == 2 :> StringTemplate["`1`nd"][seconds],
thirds_Integer /; Mod[thirds, 10] == 3 :> StringTemplate["`1`rd"][thirds],
rest_Integer :> StringTemplate["`1`th"][rest] }
(* { "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th",
"10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th",
"18th", "19th", "20th", "21st", "22nd", "23rd", "24th", "25th",
"26th", "27th", "28th", "29th", "30th", "31st", "32nd", "33rd",
"34th", "35th", "36th", "37th", "38th", "39th", "40th", "41st",
"42nd", "43rd", "44th", "45th", "46th", "47th", "48th", "49th",
"50th", "51st", "52nd", "53rd", "54th", "55th", "56th", "57th",
"58th", "59th", "60th", "61st", "62nd", "63rd", "64th", "65th",
"66th", "67th", "68th", "69th", "70th", "71st", "72nd", "73rd",
"74th", "75th", "76th", "77th", "78th", "79th", "80th", "81st",
"82nd", "83rd", "84th", "85th", "86th", "87th", "88th", "89th",
"90th", "91st", "92nd", "93rd", "94th", "95th", "96th", "97th",
"98th", "99th", "100th", "101st", "102nd", "103rd", "104th",
"105th", "106th", "107th", "108th", "109th", "110th", "111th",
"112th", "113th", "114th", "115th", "116th", "117th", "118th",
"119th", "120th" } *)
A brute force but very simple approach (no undocumented functions needed) that I think will work with any version of Mathematica.
ordinalRule[n_Integer /; Mod[n, 100] == 11] := generalRule[n]
ordinalRule[n_Integer /; Mod[n, 100] == 12] := generalRule[n]
ordinalRule[n_Integer /; Mod[n, 100] == 13] := generalRule[n]
ordinalRule[n_Integer /; Mod[n, 10] == 1] = specialRule1[n];
ordinalRule[n_Integer /; Mod[n, 10] == 2] = specialRule2[n];
ordinalRule[n_Integer /; Mod[n, 10] == 3] = specialRule3[n];
ordinalRule[n_Integer] = generalRule[n];
specialRule1[n_] := n -> (ToString[n] <> "st")
specialRule2[n_] := n -> (ToString[n] <> "nd")
specialRule3[n_] := n -> (ToString[n] <> "rd")
generalRule[n_] := n -> (ToString[n] <> "th")
ordinalRule /@ Range @ 130
{1 -> "1st", 2 -> "2nd", 3 -> "3rd", 4 -> "4th", 5 -> "5th", 6 -> "6th", 7 -> "7th", 8 -> "8th", 9 -> "9th", 10 -> "10th", 11 -> "11th", 12 -> "12th", 13 -> "13th", 14 -> "14th", 15 -> "15th", 16 -> "16th", 17 -> "17th", 18 -> "18th", 19 -> "19th", 20 -> "20th", 21 -> "21st", 22 -> "22nd", 23 -> "23rd", 24 -> "24th", 25 -> "25th", 26 -> "26th", 27 -> "27th", 28 -> "28th", 29 -> "29th", 30 -> "30th", 31 -> "31st", 32 -> "32nd", 33 -> "33rd", 34 -> "34th", 35 -> "35th", 36 -> "36th", 37 -> "37th", 38 -> "38th", 39 -> "39th", 40 -> "40th", ... 91 -> "91st", 92 -> "92nd", 93 -> "93rd", 94 -> "94th", 95 -> "95th", 96 -> "96th", 97 -> "97th", 98 -> "98th", 99 -> "99th", 100 -> "100th", 101 -> "101st", 102 -> "102nd", 103 -> "103rd", 104 -> "104th", 105 -> "105th", 106 -> "106th", 107 -> "107th", 108 -> "108th", 109 -> "109th", 110 -> "110th", 111 -> "111th", 112 -> "112th", 113 -> "113th", 114 -> "114th", 115 -> "115th", 116 -> "116th", 117 -> "117th", 118 -> "118th", 119 -> "119th", 120 -> "120th", 121 -> "121st", 122 -> "122nd", 123 -> "123rd", 124 -> "124th", 125 -> "125th", 126 -> "126th", 127 -> "127th", 128 -> "128th", 129 -> "129th", 130 -> "130th"}
<>
for string concatenation! I forgot it and just used templating. :)
$\endgroup$
Short answer: As of Version 10 there is IntegerName
, but it has to be slightly modified to be really helpful for ordinal numbers.
IntegerName
allows to provide qualifiers and combinations of these. Unfortunately, using "Ordinal"
will not give a correctly spelled result since there is no "and" as in "one hundred and first" (cf. here).
Furthermore, you cannot obtain a "DigitsWords"
-like output (e.g. "101st" ) for ordinal numbers by doing IntegerName[ 101, {"DigitsWords", "Ordinal" }]
or IntegerName[ 101, {"Ordinal", "DigitsWords" } ]
even though the documentation looks like combining qualifiers for IntegerName
in this way should be possible.
But tweaking IntegerName
slightly within a custom build converter function will get us what we want:
IntegerNameOrdinal[ i_Integer ] := With[
{
stringPatternTwoDigits = IntegerName[ Range[1, 99], "Ordinal"]
}
,
IntegerName[ i, "Ordinal" ] // StringReplace[
( a__ /; StringFree[a, "-"] ) ~~ b:stringPatternTwoDigits :> a ~~ "and " ~~ b
]
]
IntegerNameOrdinal[ i_Integer, "DigitsWords" ] := Module[
{
strEnding = IntegerName[ i, "Ordinal" ] // StringTake[ # ,-2 ]&,
strDigits = ToString @ i
}
,
strDigits ~~ strEnding
]
IntegerNameOrdinal[ i_Integer, ___ ] := IntegerNameOrdinal[ i ]
Now, we get:
IntegerNameOrdinal[ 2000232, "Words" ] (* or simply: IntegerNameOrdinal[ 2000232 ] *)
"two million two hundred and thirty-second"
IntegerNameOrdinal[ #, "DigitsWords" ]& /@ Range[ 100 ]
{"1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th", "30th", "31st", "32nd", "33rd", "34th", "35th", "36th", "37th", "38th", "39th", "40th", "41st", "42nd", "43rd", "44th", "45th", "46th", "47th", "48th", "49th", "50th", "51st", "52nd", "53rd", "54th", "55th", "56th", "57th", "58th", "59th", "60th", "61st", "62nd", "63rd", "64th", "65th", "66th", "67th", "68th", "69th", "70th", "71st", "72nd", "73rd", "74th", "75th", "76th", "77th", "78th", "79th", "80th", "81st", "82nd", "83rd", "84th", "85th", "86th", "87th", "88th", "89th", "90th", "91st", "92nd", "93rd", "94th", "95th", "96th", "97th", "98th", "99th", "100th"}
ordinalizeF = Module[{mod = Boole[!MemberQ[{11, 12}, Mod[Abs[#], 100]] ] Mod[Abs[#], 10]},
With[{suffix = Switch[mod, 1, "st", 2, "nd", 3, "rd", _, "th"]}, Row[{ToString@#, suffix}]]] &;
ordinalizeF /@ {1, 2, 3, 11, -12, 21, 33, 5542}
(* {1st, 2nd, 3rd, 11th, -12th, 21st, 33rd, 5542nd} *)
Thread[# -> ordinalizeF /@ #] &@{1, 2, 3, 11, -12, 21, 33, 542}
(*{1 -> 1st, 2 -> 2nd, 3 -> 3rd, 11 -> 11th, -12 -> -12th, 21 -> 21st, 33 -> 33rd, 542-> 542nd} *)
The IntegerName
function was upgraded in 2017 with version 11.1
according to the doc page.
So here is an implementation for ordinal numbers as requested in the OP.
For languages where gender affects grammatical units, example usage is as follows:
IntegerName[#, {"Italian", "Ordinal", "Feminine"}] & /@ Range[0, 10]
{"zeresima", "prima", "seconda", "terza", "quarta", "quinta",
"sesta", "settima", "ottava", "nona", "decima"}
IntegerName[#, {"Italian", "Ordinal", "Masculine"}] & /@ Range[0, 10]
{"zeresimo", "primo", "secondo", "terzo", "quarto", "quinto",
"sesto", "settimo", "ottavo", "nono", "decimo"}
For English, the usage is simpler.
IntegerName[#, "Ordinal"] & /@ Catenate[{Range[0, 20],
Range[30, 100, 10]}]
{"zeroth", "first", "second", "third", "fourth", "fifth", "sixth",
"seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth",
"thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth",
"eighteenth", "nineteenth", "twentieth", "thirtieth", "fortieth",
"fiftieth", "sixtieth", "seventieth", "eightieth", "ninetieth", "one
hundredth"}
To use the shorter form such as 1st
, 2nd
etc., the last two letters can be extracted from the above using StringTake
.
StringJoin @@@ ({IntegerString[#],
StringTake[IntegerName[#, "Ordinal"], -2]} & /@ Range[0, 100])
{"0th", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th",
"9th", "10th", "11th", "12th", "13th", "14th", "15th", "16th",
"17th", "18th", "19th", "20th", "21st", "22nd", "23rd", "24th",
"25th", "26th", "27th", "28th", "29th", "30th", "31st", "32nd",
"33rd", "34th", "35th", "36th", "37th", "38th", "39th", "40th",
"41st", "42nd", "43rd", "44th", "45th", "46th", "47th", "48th",
"49th", "50th", "51st", "52nd", "53rd", "54th", "55th", "56th",
"57th", "58th", "59th", "60th", "61st", "62nd", "63rd", "64th",
"65th", "66th", "67th", "68th", "69th", "70th", "71st", "72nd",
"73rd", "74th", "75th", "76th", "77th", "78th", "79th", "80th",
"81st", "82nd", "83rd", "84th", "85th", "86th", "87th", "88th",
"89th", "90th", "91st", "92nd", "93rd", "94th", "95th", "96th",
"97th", "98th", "99th", "100th"}
The resource function OrdinalNumberString
from this page is available, but using it hanged my system. I am using v12.2.0-Win7-x64.
IntegerName
but it needs to be tweaked to give what you/we want. $\endgroup$ResourceFunction["OrdinalNumberString"]
from the Wolfram Resource Library. $\endgroup$