I would like to generate (as a return result of a function, or simply as the output of a program) the ordinal suffix of a positive integer concatenated to the number.
Samples:
1st
2nd
3rd
4th
...
11th
12th
13th
...
20th
21st
22nd
23rd
24th
And so on, with the suffix repeating the initial 1-10 subpattern every 10 until 100, where the pattern ultimately starts over.
The input would be the number and the output the ordinal string as shown above.
What is the smallest algorithm for this?
51 Answers 51
Python 2, 49 bytes
lambda n:`n`+'tsnrhtdd'[n%5*(n%100^15>4>n%10)::4]
An anonymous function. A full program would be counted at 55 bytes.
'tsnrhtdd'[i::4] encodes the suffixes th st nd rd for values of i from 0 to 3. Given this, all we need is a way to map the values of n to the index of the corresponding suffix, i. A straightforward expression that works is (n%10)*(n%10<4 and not 10<n%100<14). We can easily shorten this by dropping the first set of parentheses and observing that n%5 gives the same results as n%10 for the values of n with the special suffixes. With a bit of trial and error, one may also shorten not 10<n%100<14 to n%100^15>4, which can be chained with the other conditional to save even more bytes.
-
6\$\begingroup\$ this is some black magic right here c: \$\endgroup\$cat– cat2016年02月25日 23:33:09 +00:00Commented Feb 25, 2016 at 23:33
-
\$\begingroup\$ terminally-incoherent.com/blog/wp-content/uploads/2012/08/… \$\endgroup\$Morgan Thrapp– Morgan Thrapp2016年02月26日 17:10:34 +00:00Commented Feb 26, 2016 at 17:10
-
\$\begingroup\$ the straightforward expression looks to have a mistake: the index should be non-zero if n%100 is not between 10 and 14. \$\endgroup\$je je– je je2022年06月28日 23:40:27 +00:00Commented Jun 28, 2022 at 23:40
-
\$\begingroup\$ @jeje Good eye! I fixed up the explanation. Funny how this error has gone unnoticed for so many years. \$\endgroup\$xsot– xsot2022年06月30日 14:24:14 +00:00Commented Jun 30, 2022 at 14:24
Perl, 37 + 1 characters
s/1?\d\b/$&.((0,st,nd,rd)[$&]||th)/eg
This is a regexp substitution that appends the appropriate ordinal suffix to any numbers in $_ that are not already followed by a letter. To apply it to file input, use the p command line switch, like this:
perl -pe 's/1?\d\b/$&.((0,st,nd,rd)[$&]||th)/eg'
This is a complete Perl program that reads input from stdin and writes the processed output to stdout. The actual code is 37 chars long, but the p switch counts as one extra character.
Sample input:
This is the 1 line of the sample input...
...and this is the 2.
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
101 102 103 104 105 106 107 108 109 110
Output:
This is the 1st line of the sample input...
...and this is the 2nd.
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
101st 102nd 103rd 104th 105th 106th 107th 108th 109th 110th
Numbers already followed by letters will be ignored, so feeding the output again through the filter won't change it. Spaces, commas and periods between numbers are not treated specially, so they're assumed to separate numbers like any other punctuation. Thus, e.g. 3.14159 becomes 3rd.14159th.
How does it work?
First, this is a global regexp replacement (
s///g). The regexp being matched is1?\d\b, where\dmatches any digit and\bis a zero-width assertion matching the boundary between an alphanumeric and a non-alphanumeric character. Thus,1?\d\bmatches the last digit of any number, plus the previous digit if it happens to be1.In the substitution, which is evaluated as Perl code due to the
/eswitch, we take the matched string segment ($&) and append (.) to it the suffix obtained by using$&itself as an integer index to the list(0,st,nd,rd); if this suffix is zero or undefined (i.e. when$&is zero or greater than three), the||operator replaces it withth.
Edit: If the input is restricted to a single integer, then this 35 character solution will suffice:
s/1?\d$/$&.((0,st,nd,rd)[$&]||th)/e
-
1\$\begingroup\$ Should be able to drop the
goff the substitution if you specify that each number must be on it's own line. Also, that'd let you change the word boundary to be$. But overall, +1, damn clever solution. \$\endgroup\$Mr. Llama– Mr. Llama2012年01月20日 21:05:11 +00:00Commented Jan 20, 2012 at 21:05 -
\$\begingroup\$ @GigaWatt: Indeed, I wrote the code before NickC answered my question about the input format, so I made it as generic as possible. \$\endgroup\$Ilmari Karonen– Ilmari Karonen2012年01月20日 21:42:16 +00:00Commented Jan 20, 2012 at 21:42
-
\$\begingroup\$ I know this is pretty old and rules were different, but using
$\instead ofs///shaves a few bytes off: Try it online! \$\endgroup\$Dom Hastings– Dom Hastings2020年07月05日 07:48:35 +00:00Commented Jul 5, 2020 at 7:48 -
\$\begingroup\$ In fact, even shorter using
/.../gsyntax: Try it online! \$\endgroup\$Dom Hastings– Dom Hastings2020年07月06日 12:41:55 +00:00Commented Jul 6, 2020 at 12:41
Python, 68 characters
i=input()
k=i%10
print"%d%s"%(i,"tsnrhtdd"[(i/10%10!=1)*(k<4)*k::4])
-
5\$\begingroup\$ This is really late, but you can take off 7 bytes by doing
`i`+"tsnrhtdd". Otherwise, this is the exact solution I just got. \$\endgroup\$DLosc– DLosc2015年09月05日 20:27:28 +00:00Commented Sep 5, 2015 at 20:27
Mathematica (削除) 39 (削除ここまで) 45 bytes
Note: In recent versions of Mathematica, asking for the nth part of p, where p is undefined, generates an error message, but returns the correct answer anyway. I've added Quiet to prevent the error message from printing.
Quiet@StringSplit[SpokenString[p[[#]]]][[2]]&
Usage
Quiet@StringSplit[SpokenString[p[[#]]]][[2]] &[31]
31st
Quiet@StringSplit[SpokenString[p[[#]]]][[2]] &/@Range[21]
{"1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th", "21st"}
How it works
SpokenString writes out an any valid Mathematica expression as it might be spoken. Below are two examples from the documentation for SpokenString,
SpokenString[Sqrt[x/(y + z)]]
"square root of the quantity x over the quantity y plus z" *)
SpokenString[Graphics3D[Sphere[{{0, 0, 0}, {1, 1, 1}}]], "DetailedGraphics" -> True]
"a three-dimensional graphic consisting of unit spheres centered at 0, 0, 0 and 1, 1, 1"
Now, for the example at hand,
Quiet@SpokenString[p[[#]]] &[31]
"the 31st element of p"
Let's represent the above string as a list of words:
StringSplit[%]
{"the", "31st", "element", "of", "p"}
and take the second element...
%[[2]]
31st
-
\$\begingroup\$ I'm confused; where is
pdefined? EDIT: never mind, I see how you're using this; unfortunately it does not work on my system. :-/ \$\endgroup\$Mr.Wizard– Mr.Wizard2013年04月06日 13:13:45 +00:00Commented Apr 6, 2013 at 13:13 -
\$\begingroup\$ It works on v.9.0.1. (I seem to recall that you are using 7.0.) Yes, p does not need to be defined. \$\endgroup\$DavidC– DavidC2013年04月06日 13:29:47 +00:00Commented Apr 6, 2013 at 13:29
-
\$\begingroup\$ I understand that now. However, in v7 I get from
SpokenString @ p[[117]]the output" part 117 of p". \$\endgroup\$Mr.Wizard– Mr.Wizard2013年04月06日 13:31:46 +00:00Commented Apr 6, 2013 at 13:31 -
\$\begingroup\$ So
SpokenStringgets revised from time to time. I wouldn't be surprised it this code (codegolf.stackexchange.com/questions/8859/…) also doesn't work on v. 7. BTW, it wasn't meant to be an enduring solution. \$\endgroup\$DavidC– DavidC2013年04月06日 13:37:19 +00:00Commented Apr 6, 2013 at 13:37 -
\$\begingroup\$ Hah, I hadn't seen that answer before. \$\endgroup\$Mr.Wizard– Mr.Wizard2013年04月06日 13:44:16 +00:00Commented Apr 6, 2013 at 13:44
Javascript (ES6) (削除) 50 (削除ここまで) 44 Bytes
a=>a+=[,"st","nd","rd"][a.match`1?.$`]||"th"
Notes
- takes imput as a string
- Removed 6 bytes, thanks @user81655
-
4\$\begingroup\$
a+->a+=, remove parentheses,\d->., remove[0], and if you take the number as a string:a.match`1?.$`instead of/1?.$/.exec(a). \$\endgroup\$user81655– user816552016年02月26日 21:49:09 +00:00Commented Feb 26, 2016 at 21:49
Ruby, 60
It's not as good as the Perl entry, but I figured I'd work on my Ruby skills.
def o(n)n.to_s+%w{th st nd rd}[n/10%10==1||n%10>3?0:n%10]end
Function takes one integer argument, n, and returns a string as the ordinal form.
Works according to the following logic:
If the tens digit is a 1 or the ones digit is greater than 3 use the suffix 'th'; otherwise find the suffix from the array ['th', 'st', 'nd', 'rd'] using the final digit as the index.
-
\$\begingroup\$
o(113)is"113rd", should be"113th". The tens digit check doesn't account for numbers with more than two digits. \$\endgroup\$hammar– hammar2012年01月20日 23:07:19 +00:00Commented Jan 20, 2012 at 23:07 -
\$\begingroup\$ Ok, pitched in another
%10to compensate. Added 3 characters. (I feel like%10appears enough where it should be shortened somehow, but I can't think of a solution) \$\endgroup\$Mr. Llama– Mr. Llama2012年01月20日 23:12:00 +00:00Commented Jan 20, 2012 at 23:12 -
1\$\begingroup\$ You can never beat Perl in writing horrible incomprehensible code that's as short as possible :) \$\endgroup\$jamylak– jamylak2013年04月06日 10:25:11 +00:00Commented Apr 6, 2013 at 10:25
-
\$\begingroup\$ Set a variable to
10? \$\endgroup\$wizzwizz4– wizzwizz42016年02月25日 17:57:34 +00:00Commented Feb 25, 2016 at 17:57 -
\$\begingroup\$ I think setting a variable to
n%10is better. \$\endgroup\$CalculatorFeline– CalculatorFeline2016年02月27日 20:53:30 +00:00Commented Feb 27, 2016 at 20:53
Javascript, (削除) 68 (削除ここまで) 71
function o(n){return n+([,'st','nd','rd'][~~(n/10%10)-1?n%10:0]||'th')}
Joint effort with ItsCosmo.
EDIT: Wasn't working properly with numbers > 100
-
\$\begingroup\$ You could bring it down to 62 with:
function o(n)n+([,'st','nd','rd'][~~(n/10%10)-1?n%10:0]||'th')and you can bring it down further to 54 if you are happy to use fat arrow notation:o=n=>n+([,'st','nd','rd'][~~(n/10%10)-1?n%10:0]||'th')\$\endgroup\$Eliseo D'Annunzio– Eliseo D'Annunzio2014年03月03日 12:04:19 +00:00Commented Mar 3, 2014 at 12:04 -
\$\begingroup\$ @WallyWest For some reason, I really like that my solution works in modern browsers. Feel free to post your own answer; I think its sufficiently different. \$\endgroup\$aebabis– aebabis2014年03月03日 16:33:45 +00:00Commented Mar 3, 2014 at 16:33
-
\$\begingroup\$ No, that's fine! Just providing a few alternatives! \$\endgroup\$Eliseo D'Annunzio– Eliseo D'Annunzio2014年03月03日 23:20:42 +00:00Commented Mar 3, 2014 at 23:20
-
\$\begingroup\$ I made it work with ARGV:
for(n of arguments)print(n+([,'st','nd','rd'][~~(n/10%10)-1?n%10:0]||'th'))\$\endgroup\$DaCuteRaccoon– DaCuteRaccoon2022年05月06日 01:57:44 +00:00Commented May 6, 2022 at 1:57
JavaScript, 64 characters (ES3) or 47 characters (ES6)
ES3 (64 characters):
function(n){return n+=[,'st','nd','rd'][n%100>>3^1&&n%10]||'th'}
ES6 (47 characters):
n=>n+=[,'st','nd','rd'][n%100>>3^1&&n%10]||'th'
Explanation
The expression n % 100 >> 3 ^ 1 evaluates to 0 for any positive n ending with digits 08–15. Thus, for any n mod 100 ending in 11, 12, or 13, the array lookup returns undefined, leading to a suffix of th.
For any positive n ending in other digits than 08–15, the expression n % 100 >> 3 ^ 1 evaluates to a positive integer, invoking the expression n % 10 for array lookup, returning st,nd, or rd for n which ends with 1, 2, or 3. Otherwise, th.
-
\$\begingroup\$ Save a bytes with
n+=[,'st','nd','rd'][n%100>>3^1&&n%10]||'th'. \$\endgroup\$Shaggy– Shaggy2017年05月08日 13:29:54 +00:00Commented May 8, 2017 at 13:29 -
1\$\begingroup\$ FYI github.com/guest271314/SpeechSynthesisSSMLParser/blob/master/…, github.com/guest271314/SpeechSynthesisSSMLParser/blob/master/… \$\endgroup\$guest271314– guest2713142018年12月15日 21:42:58 +00:00Commented Dec 15, 2018 at 21:42
-
\$\begingroup\$ @guest271314, fun to see this code being used. Note that it only works for positive numbers, another alternative is
n+=[,"st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10]||"th", adapted from this post. \$\endgroup\$Tomas Langkaas– Tomas Langkaas2018年12月20日 11:15:38 +00:00Commented Dec 20, 2018 at 11:15
Haskell, (削除) 95 (削除ここまで) 100 chars
h=foldr g"th".show
g '1'"th"="1st"
g '2'"th"="2nd"
g '3'"th"="3rd"
g '1'[x,_,_]='1':x:"th"
g a s=a:s
Testing:
*Main> map h [1..40]
["1st","2nd","3rd","4th","5th","6th","7th","8th","9th","10th","11th","12th","13t
h","14th","15th","16th","17th","18th","19th","20th","21st","22nd","23rd","24th",
"25th","26th","27th","28th","29th","30th","31st","32nd","33rd","34th","35th","36
th","37th","38th","39th","40th"]
Must be loaded with -XNoMonomorphismRestriction.
-
\$\begingroup\$ I'm seeing 100 here, but 95 using an infix operator. \$\endgroup\$Khuldraeseth na'Barya– Khuldraeseth na'Barya2020年07月05日 15:48:40 +00:00Commented Jul 5, 2020 at 15:48
-
\$\begingroup\$ thanks, fixed. probably didn't know we have to count the newlines as well, back then. \$\endgroup\$Will Ness– Will Ness2020年07月06日 10:29:31 +00:00Commented Jul 6, 2020 at 10:29
Golfscript, 34 characters
~.10/10%1=!110ドル%*.4<*'thstndrd'2/=
J - (削除) 44 (削除ここまで) 41 char
Nothing in J? This is an outrage!
(":,th`st`nd`rd{::~4|4<.10(|*|~:-~)100&|)
Explained (note that 1 is boolean true in J and 0 is false):
100&|- First, reduce the input modulo 100.10(|*|~:-~)- In this subexpression,|is the input mod 10 and-~is the input (mod 100) minus 10. You don't get many trains as clean as this one in J, so it's a treat to see here!~:is not-equals, so|~:-~is false if the tens digit is 1 and true otherwise.*is just multiplication, so we're taking the input mod 10 and multiplying by a boolean, which will zero it out if false. The result of this is "input mod 10, except 0 on the tens".
4|4<.- Min (<.) the above with 4, to clamp down larger values, and then reduce modulo 4 so that they all go to zero.th`st`nd`rd{::~- Use that as an index into the list of suiffixes. Numbers ending in X1 or X2 or X3, but not in 1X, will find their suffix, and everything else will take the 0th suffixth.":,- Finally, take the original input, convert it to a string (":), and append the suffix.
Usage is obvious, though as-is the verb can only take one ordinal, not a list.
(":,th`st`nd`rd{::~4|4<.10(|*|~:-~)100&|) 112 NB. single use
112th
(":,th`st`nd`rd{::~4|4<.10(|*|~:-~)100&|) 1 2 3 4 5 NB. doing it wrong
|length error
| (":,th`st`nd`rd{::~4|4<.10(|*|~:-~)100&|)1 2 3 4 5
NB. i.5 10 makes a 5x10 grid of increasing integers
NB. &.> to operate on each integer separately, and box the result after
(":,th`st`nd`rd{::~4|4<.10(|*|~:-~)100&|)&.> i.5 10 NB. all better
+----+----+----+----+----+----+----+----+----+----+
|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|
+----+----+----+----+----+----+----+----+----+----+
Alternative 41 char solution showing off a couple logical variants:
(":;@;st`nd`rd`th{~3<.10(|+3*|=-~)100|<:)
Previously I had an overlong explanation of this 44 char hunk of junk. 10 10#: takes the last two decimal digits and /@ puts logic between them.
(":,th`st`nd`rd{::~10 10(]*[(~:*])4>])/@#:])
PowerShell, 92
process{"$_$(switch -r($_){"(?<!1)1$"{'st'}"(?<!1)2$"{'nd'}"(?<!1)3$"{'rd'}default{'th'}})"}
Works with one number per line of input. Input is given through the pipeline. Making it work for only a single number doesn't reduce the size.
R, (削除) 79 (削除ここまで) 76 bytes
Since there is no R solution yet... no tricks here, basic vector indexing, golfed down 3 chars thanks to Giuseppe. Previously tried index: [1+(x%%10)-(x%%100==11)] and [1+(x%%10)*(x%%100!=11)].
function(x)paste0(x,c("th","st","nd","rd",rep("th",6))[1+x%%10*!x%%100==11])
With substr, 79 bytes:
function(x,y=1+2*min(x%%10-(x%%100==11),4))paste0(x,substr("thstndrdth",y,y+1))
-
1\$\begingroup\$
1+x%%10*!x%%100==11for the index? \$\endgroup\$Giuseppe– Giuseppe2018年05月03日 17:58:25 +00:00Commented May 3, 2018 at 17:58 -
\$\begingroup\$ @Giuseppe I need to calm down on the parenthesis :). Clever use of
!in front of expression instead of!=. \$\endgroup\$JayCe– JayCe2018年05月03日 18:13:23 +00:00Commented May 3, 2018 at 18:13 -
1\$\begingroup\$ Yeah, the operators have weird precedence;
^is really high, then%%-type operators, then*/and+-and I think==and&|comes next.!has quite low precedence so you can use it as a separator between operations. \$\endgroup\$Giuseppe– Giuseppe2018年05月03日 18:17:44 +00:00Commented May 3, 2018 at 18:17
APL (Dyalog Unicode), (削除) 38 (削除ここまで) 36 bytes
Thanks to ngn for fixing a bug while maintaining byte count.
Anonymous tacit prefix function. Requires ⎕IO (Index Origin) set to 0, which is default on many systems. Even works for 0!
⍕,{2↑'thstndrd×ばつ⊃⍵⌽∊1 0 8\⊂10↑⍳4}
{...} anonymous lambda; ⍵ is argument:
⍳4 first four ɩndices; [0,1,2,3]
10↑ take first ten elements from that, padding with zeros: [0,1,2,3,0,0,0,0,0,0]
⊂ enclose to treat as single element; [[0,1,2,3,0,0,0,0,0,0]]
1 0 8\ expand to one copy, a prototypical copy (all-zero), eight copies;
[[0,1,2,3,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,1,2,3,0,0,0,0,0,0],
[0,1,2,3,0,0,0,0,0,0],
⋮ (5 more)
[0,1,2,3,0,0,0,0,0,0]]
∊ εnlist (flatten);
[0,1,2,3,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,1,2,3,0,0,0,0,0,0,
0,1,2,3,0,0,0,0,0,0,
⋮ (50 more)
0,1,2,3,0,0,0,0,0,0]
⍵⌽ cyclically rotate left as many steps as indicated by the argument
⊃ pick the first number (i.e. the argument-mod-100'th number)
×ばつ multiply two by that (gives 0, 2, 4, or 6)
'thstndrd'↓⍨drop that many characters from this string
2↑ take the first two of the remaining characters
⍕, concatenate the stringified argument to that
-
\$\begingroup\$ "31th"? \$\endgroup\$ngn– ngn2018年05月03日 17:49:53 +00:00Commented May 3, 2018 at 17:49
-
\$\begingroup\$
⍕,{2↑'thstndrd'↓⍨2×⊃⍵⌽∊1 0 8\⊂10↑⍳4}\$\endgroup\$ngn– ngn2018年05月03日 18:23:04 +00:00Commented May 3, 2018 at 18:23 -
\$\begingroup\$ sorry, I forgot to mention
⎕io←0. I can see you guessed that, but there are a few 1,2,3,4,0,0... that should be 0,1,2,3,0,0... \$\endgroup\$ngn– ngn2018年05月03日 19:35:21 +00:00Commented May 3, 2018 at 19:35 -
\$\begingroup\$ @ngn Fixed. And happens to work for 0 too! \$\endgroup\$Adám– Adám2018年05月03日 20:26:17 +00:00Commented May 3, 2018 at 20:26
Javascript, (削除) 75 (削除ここまで) 60
With the new arrow notation:
o=(s)=>s+((0|s/10%10)==1?"th":[,"st","nd","rd"][s%10]||"th")
Old version, without arrow notation (75 chars):
function o(s){return s+((0|s/10%10)==1?"th":[,"st","nd","rd"][s%10]||"th")}
-
1\$\begingroup\$ 52 bytes (V8) \$\endgroup\$user100411– user1004112021年06月18日 12:23:50 +00:00Commented Jun 18, 2021 at 12:23
Bash (Cardinal to ordinal) 91 Bytes:
function c(){ case "1ドル" in *1[0-9]|*[04-9])"1ドル"th;;*1)"1ドル"st;;*2)"1ドル"nd;;*3)"1ドル"rd;;esac }
-
1\$\begingroup\$ You can save at least 2 bytes in your solution, just rename your
c2ofunction something with a 1-byte name. \$\endgroup\$RGS– RGS2020年07月05日 09:45:13 +00:00Commented Jul 5, 2020 at 9:45 -
1\$\begingroup\$ 58 bytes. \$\endgroup\$user100411– user1004112021年06月18日 11:53:34 +00:00Commented Jun 18, 2021 at 11:53
-
\$\begingroup\$ Wow @tailsparkrabbitear I think you should write an answer. Or do you want me to edit my answer? \$\endgroup\$stephanmg– stephanmg2021年06月18日 12:06:02 +00:00Commented Jun 18, 2021 at 12:06
-
1\$\begingroup\$ If you say so; posted mine. \$\endgroup\$user100411– user1004112021年06月18日 12:18:12 +00:00Commented Jun 18, 2021 at 12:18
PHP, 151
I know that this program is not comparable to the others. Just felt like giving a solution.
<?$s=explode(' ',trim(fgets(STDIN)));foreach($s as$n){echo$n;echo(int)(($n%100)/10)==1?'th':($n%10==1?'st':($n%10==2?'nd':($n%10==3?'rd':'th')))."\n";}
-
\$\begingroup\$ you can save a few characters by using
foreach($s as $n){echo$n;\$\endgroup\$karth– karth2012年04月29日 11:24:53 +00:00Commented Apr 29, 2012 at 11:24
K - 44 char
It so happens that this is exactly as long as the J, and works in almost the same way.
{x,$`th`st`nd`rd@{y*(y<4)*~1=x}.-2#0,.:'x$:}
Explained:
x$:- First, we convert the operandxinto a string, and then assign that back tox. We will need its string rep again later, so doing it now saves characters..:'- Convert (.:) each (') digit back into a number.-2#0,- Append a 0 to the front of the list of digits (in case of single-digit numbers), and then take the last two.{y*(y<4)*~1=x}.- Use the two digits as argumentsxandyto this inner function, which returnsyifyis less than 4 andxis not equal to 1, otherwise 0.`th`st`nd`rd@- Index the list of suffixes by this result.x,$- Convert the suffix from symbol to string, and append it to the original number.
Usage:
{x,$`th`st`nd`rd@{y*(y<4)*~1=x}.-2#0,.:'x$:} 3021
"3021st"
{x,$`th`st`nd`rd@{y*(y<4)*~1=x}.-2#0,.:'x$:}' 1 2 3 4 11 12 13 14 /for each in list
("1st"
"2nd"
"3rd"
"4th"
"11th"
"12th"
"13th"
"14th")
PHP, 98 bytes
function c($n){$c=$n%100;$s=['','st','nd','rd'];echo$c>9&&$c<14||!$s[$c%10]?$n.'th':$n.$s[$c%10];}
The 11-13 bit is killing me here. Works for any integer $n >= 0.
For any integer $n:
PHP, 103 bytes
function c($n){$c=abs($n%100);$s=['','st','nd','rd'];echo$c>9&&$c<14||!$s[$c%10]?$n.'th':$n.$s[$c%10];}
Javascript ES6, 52 chars
n=>n+(!/1.$/.test(--n)&&'snr'[n%=10]+'tdd'[n]||'th')
C#, 62 bytes
n=>n+(n/10%10==1||(n%=10)<1||n>3?"th":n<2?"st":n<3?"nd":"rd");
Full program and verification:
using System;
namespace OutputOrdinalNumbers
{
class Program
{
static void Main(string[] args)
{
Func<int,string>f= n=>n+(n/10%10==1||(n%=10)<1||n>3?"th":n<2?"st":n<3?"nd":"rd");
for (int i=1; i<=124; i++)
Console.WriteLine(f(i));
}
}
}
-
1\$\begingroup\$ You can golf it by two bytes by changing the
||to|. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2016年11月08日 12:39:20 +00:00Commented Nov 8, 2016 at 12:39
Mathematica 29 + 5 = 34 bytes
SpokenStringDump`SpeakOrdinal
+5 bytes because Speak function must be called before using this built-in.
Usage
SpokenStringDump`SpeakOrdinal[1]
"1st "
SpokenStringDump`SpeakOrdinal[4707]
"4,707th "
Java 7, (削除) 91 (削除ここまで) 81 bytes
String d(int n){return n+(n/10%10==1|(n%=10)<1|n>3?"th":n<2?"st":n<3?"nd":"rd");}
Port from @adrianmp's C# answer.
Old answer (91 bytes):
String c(int n){return n+((n%=100)>10&n<14?"th":(n%=10)==1?"st":n==2?"nd":n==3?"rd":"th");}
Ungolfed & test code:
class M{
static String c(int n){
return n + ((n%=100) > 10 & n < 14
?"th"
: (n%=10) == 1
? "st"
: n == 2
? "nd"
: n == 3
? "rd"
:"th");
}
static String d(int n){
return n + (n/10%10 == 1 | (n%=10) < 1 | n > 3
? "th"
: n < 2
? "st"
: n < 3
? "nd"
:"rd");
}
public static void main(String[] a){
for(int i = 1; i < 201; i++){
System.out.print(c(i) + ", ");
}
System.out.println();
for(int i = 1; i < 201; i++){
System.out.print(d(i) + ", ");
}
}
}
Output:
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, 121st, 122nd, 123rd, 124th, 125th, 126th, 127th, 128th, 129th, 130th, 131st, 132nd, 133rd, 134th, 135th, 136th, 137th, 138th, 139th, 140th, 141st, 142nd, 143rd, 144th, 145th, 146th, 147th, 148th, 149th, 150th, 151st, 152nd, 153rd, 154th, 155th, 156th, 157th, 158th, 159th, 160th, 161st, 162nd, 163rd, 164th, 165th, 166th, 167th, 168th, 169th, 170th, 171st, 172nd, 173rd, 174th, 175th, 176th, 177th, 178th, 179th, 180th, 181st, 182nd, 183rd, 184th, 185th, 186th, 187th, 188th, 189th, 190th, 191st, 192nd, 193rd, 194th, 195th, 196th, 197th, 198th, 199th, 200th,
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, 121st, 122nd, 123rd, 124th, 125th, 126th, 127th, 128th, 129th, 130th, 131st, 132nd, 133rd, 134th, 135th, 136th, 137th, 138th, 139th, 140th, 141st, 142nd, 143rd, 144th, 145th, 146th, 147th, 148th, 149th, 150th, 151st, 152nd, 153rd, 154th, 155th, 156th, 157th, 158th, 159th, 160th, 161st, 162nd, 163rd, 164th, 165th, 166th, 167th, 168th, 169th, 170th, 171st, 172nd, 173rd, 174th, 175th, 176th, 177th, 178th, 179th, 180th, 181st, 182nd, 183rd, 184th, 185th, 186th, 187th, 188th, 189th, 190th, 191st, 192nd, 193rd, 194th, 195th, 196th, 197th, 198th, 199th, 200th,
Python 2.7, 137 chars
def b(n):
for e,o in[[i,'th']for i in['11','12','13']+list('4567890')]+[['2','nd'],['1','st'],['3','rd']]:
if n.endswith(e):return n+o
n should be a string
I know I'm beaten by the competition here already, but I thought I'd provide my idea anyways
this just basically generates a list of key, value pairs with number (as a string) ending e and the ordinal o. It attempts to match 'th' first (hence why I didn't use a dictionary), so that it won't accidentally return 'st', for example, when it should be 'th'. This will work for any positive integer
-
1\$\begingroup\$
n[-1]==eis 5 chars shorter thann.endswith(e)\$\endgroup\$hlt– hlt2014年02月14日 11:30:34 +00:00Commented Feb 14, 2014 at 11:30
Scala 86
def x(n:Int)=n+{if(n%100/10==1)"th"else(("thstndrd"+"th"*6).sliding(2,2).toSeq(n%10))}
Scala 102:
def x(n:Int)=if((n%100)/10==1)n+"th"else if(n%10<4)n+("thstndrd".take(n+1)%5*2.drop(n%5*2))else n+"th"
102 as well:
def x(n:Int)=if((n%100)/10==1)n+"th"else if(n%10<4)n+("thstndrd".sliding(2,2).toSeq(n%10))else n+"th"
ungolfed:
def x (n: Int) =
n + { if (((n % 100) / 10) == 1) "th"
else (("thstndrd" + ("th" * 6)).sliding (2, 2).toSeq (n % 10))
}
C: 95 characters
A ridiculously long solution:
n;main(){scanf("%d",&n);printf("%d%s",n,n/10%10-1&&(n=n%10)<4&&n?n>2?"rd":n<2?"st":"nd":"th");}
It needs to be mangled more.
-
\$\begingroup\$ A user flagged this saying "is incorrect: doesn't loop at all, i.e. it works just for a given number, not _all_ numbers below it. see ideone.com/pO6UwV ." That's not a reason to flag as moderators do not judge correctness, but it may be an issue. \$\endgroup\$dmckee --- ex-moderator kitten– dmckee --- ex-moderator kitten2013年04月11日 00:00:38 +00:00Commented Apr 11, 2013 at 0:00
-
\$\begingroup\$ Based upon this comment from the question creator: "@Ilmari I am looking for 11 as input and 11th as output. I don't mind if it processes multiple lines but what I had in mind was processing just a single number. – NickC Jan 20 '12 at 21:00" it is doing what it should. I.e. it only should process a single number. \$\endgroup\$Fors– Fors2013年04月11日 04:42:21 +00:00Commented Apr 11, 2013 at 4:42
-
\$\begingroup\$ sorry for that flag; I misread the requirement, and didn't have enough rep at the time, to comment directly. Sorry again. :) \$\endgroup\$Will Ness– Will Ness2013年04月13日 19:48:11 +00:00Commented Apr 13, 2013 at 19:48
OCaml
I'm pretty new to OCaml, but this is the shortest i could get.
let n x =
let v = x mod 100 and string_v = string_of_int x in
let z = v mod 10 in
if v=11 || v=12 || v=13 then string_v^"th"
else if v = 1 || z = 1 then string_v^"st" else if v = 2 || z = 2 then string_v^"nd" else if v = 3 || z = 3 then string_v^"rd" else string_v^"th";;
I created a function n that takes a number as a parameter and does the work. Its long but thought it'd be great to have a functional example.
-
\$\begingroup\$ input: 11 would yield output: 11st \$\endgroup\$user3614– user36142012年01月23日 02:04:29 +00:00Commented Jan 23, 2012 at 2:04
-
\$\begingroup\$ yeah, you're right.. I've made the correction. Thanks \$\endgroup\$Joseph Elcid– Joseph Elcid2012年02月07日 15:42:40 +00:00Commented Feb 7, 2012 at 15:42
-
\$\begingroup\$ I've just tidied up the formatting on your code. Each line needs to be preceded by four spaces in order to be recognized as a code block. \$\endgroup\$Gareth– Gareth2012年02月07日 16:29:10 +00:00Commented Feb 7, 2012 at 16:29
-
1\$\begingroup\$ Wouldn't your first if check be shorter as
if v>10 && v<14? I'm not familiar with ocaml, but is it necessary to have thestring_vvariable be so long? \$\endgroup\$Gaffi– Gaffi2012年04月29日 03:49:10 +00:00Commented Apr 29, 2012 at 3:49 -
\$\begingroup\$ No its not necessary, I could have chosen w or x. Just wanted something meaningful. But you're right, it would have made the code a little shorter. \$\endgroup\$Joseph Elcid– Joseph Elcid2012年05月11日 13:32:15 +00:00Commented May 11, 2012 at 13:32
C - (削除) 95 (削除ここまで) 83 characters
main(n,k){scanf("%d",&n);k=(n+9)%10;printf("%d%s\n",n,k<3?"st0円nd0円rd"+3*k:"th");}
Degolfed:
main(n,k)
{
scanf("%d",&n);
k=(n+9)%10; // xx1->0, xx2->1, xx3->2
printf("%d%s\n",n,k<3?"st0円nd0円rd"+3*k:"th");
}
We could do k=(n-1)%10 instead of adding 9, but for n=0 we would get an incorrect behaviour,
because in C (-1)%10 evaluates to -1, not 9.
Javascript, 75
function s(i){return i+'thstndrd'.substr(~~(i/10%10)-1&&i%10<4?i%10*2:0,2)}
11as input, and output e.g.11th? Is each number in the input on a separate line, and should the output numbers be on separate lines too? And do we need to handle more than one line of input? \$\endgroup\$11as input and11thas output. I don't mind if it processes multiple lines but what I had in mind was processing just a single number. \$\endgroup\$