Skip to content

Instantly share code, notes, and snippets.

@furf
Forked from 140bytes/LICENSE.txt
Created May 23, 2011 02:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save furf/986113 to your computer and use it in GitHub Desktop.
Save furf/986113 to your computer and use it in GitHub Desktop.
Return the ordinal suffix for a number.
function(
a // number
){
return[
"th","st","nd","rd" // array of ordinal suffixes
][
(a=~~ // floor the value for usable index (integer)
(a<0?-a:a) // absolute value for usable index (positive)
%100) // mod 100 to ensure teens edge case is handled every century
>10&&a<14 // handle teens edge case where 11-13 return "th"
||(a%=10) // mod 10 to check ones column digit
>3 // all digits above 3 return "th"
?0 // return "th" for above cases
:a // return "th", "st", "rd" for others
]
}
function b(a){return["th","st","nd","rd"][(a=~~(a<0?-a:a)%100)>10&&a<14||(a%=10)>3?0:a]}
Copyright (c) 2011 Dave Furfero, http://furf.com
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{
"name": "ordinal",
"description": "Return the ordinal suffix for a number.",
"keywords": ["ordinal","number","suffix","string"]
}
@jed
Copy link

jed commented May 23, 2011

instead of adding an option, maybe you could also return [num,ord]? that way it's easy enough to extract what you want.

ordinal(32)[1]
ordinal(32).join('')

@furf
Copy link
Author

furf commented May 23, 2011

Interesting. I would prefer your syntax in the case where the value being passed is not stored.

32+ordinal(32) // looks a little silly

But in other cases, that syntax would be longer. If I were to support the return of the value, the optional concatenation is more terse and provides a more traditional API.

// suffix-only usage
ordinal(n)            // current suffix-only
ordinal(n)[1]         // return [value, suffix] array
ordinal(n)            // optional concatenation

// value-added usage
n+ordinal(n)          // current suffix-only
ordinal(n).join('')   // return [value, suffix] array
ordinal(n,1)          // optional concatenation

PS--I'm really digging the 140bytes project. Lots of good reads. Cheers!

@tsaniel
Copy link

tsaniel commented Oct 23, 2011

My version.

function(a){return[,"st","nd","rd"][/1?.$/.exec(a)]||"th"}

@furf
Copy link
Author

furf commented Oct 23, 2011

i like the use of the empty array member. i avoided regexp for performance. http://jsperf.com/ordinals-in-140-bytes (this code actually runs on mlb.com :)) but in the world of code golf you win!

@lsauer
Copy link

lsauer commented Oct 24, 2011

tsaniel's version add's a lot of overhead, buried in the 'regexp black-box'.

If it's code golf we play, then we can't allow ourselves defining a function to get us the decimal exponent:
d = function (i){var l=Math.log; return Math.ceil(l(i)/l(10))}

Here's a version using a map-reduce-like logic
current version here: https://gist.github.com/1308753

// JS converts string-numbers on the fly e.g. "7"&3 >3
// solution with a 'map-reduce' mindset
// similar and more concise solutions could be implemented
// a=(a+'').substr(-2); 
ord = function (a){
    //summary: cast to string, map (e.g. atomize) and reduce
    a=(a+'')                            //cast to string
    .split('')                          //atomize
    .slice(-2)                          //get the last two elements
    .reduce(                            //reduce arithmetically to a single value
        function(a,b){
            if(1==a) return 0;          //teens case -> return 0 (#el containing 'th') 
            else return b>3 ? 0 : b;    //if b>3 return 0 -> 'th'
        }
    );
    return ['th','st','nd','rd'][a];    //map number to a string
};

@furf
Copy link
Author

furf commented Oct 25, 2011

another difference between our implementations: mine is the only one to base ordinal suffix on the whole number, not the decimal. since ordinals are natural numbers [0, 1, 2, ...], i felt that the floor of the number was the meaningful part to transform. i could be wrong. i suppose it's a matter of semantics and usage which implementation works best.

so, in seeing these other implementations and thinking it through... in the case of a decimal being passed and the suffix returned being based on a transformation of the passed argument, then jed, your suggestion of returning [n, suffix] would be desirable where n is the floored number. (or n + suffix)

thanks for the posts, guys.

@tsaniel
Copy link

tsaniel commented Jan 26, 2012

New version with a bitwise trick but only supports non-negative integers:

function(a){return[,'st','nd','rd'][a%100/10^1&&a%10]||'th'}

@furf
Copy link
Author

furf commented Mar 22, 2012

21th? 22th? 23th?

@furf
Copy link
Author

furf commented Mar 22, 2012

11st? 12nd? 13rd? Keep trying! :)

@furf
Copy link
Author

furf commented Mar 22, 2012

i like tsaniels bitwise the best for all practical purposes. non-negative integers are typically all you'll need.

@williammalo
Copy link

fixd?

function(a){a+="";return(a.charAt(a.length-2)==1)?"th":[,"st","nd","rd"][a.charAt(a.length-1)]||"th"}
Edit:
made it shorter with "%"
function(a){return(a%100>10&&a%100<19)?"th":[,"st","nd","rd"][a%10]||"th"}
Edit:
I just noticed Tsaniel's function... it's shorter than mine, therefore, my function is useless... meh.

@tsaniel
Copy link

tsaniel commented Mar 23, 2012

@furf: Did you mean you find a bug? But it just works fine with me.

@williammalo
Copy link

@tsaniel no, he found a bug in my code, I deleted the original post. Your function is perfect.

@tsaniel
Copy link

tsaniel commented Mar 23, 2012

Oh I see.
Shave another byte off by the way:

function(a){return[,'st','nd','rd'][a/10%10^1&&a%10]||'th'}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment