views:

910

answers:

5

I'm wondering if there is a quick and easy way to output ordinals given a number in python.

For example, given the number 1, I'd like to output "1st", the number 2, "2nd", et cetera, et cetera.

This is for working with dates in a breadcrumb trail

Home >  Venues >  Bar Academy >  2009 >  April >  01

is what is currently shown

I'd like to have something along the lines of

Home >  Venues >  Bar Academy >  2009 >  April >  1st
+2  A: 

Except for 1st, 2nd, and 3rd, I think they all just add th... 4th, 5th, 6th, 11th, 21st ... oh, oops ;-)

I think this might work:

def ordinal(num):
     ldig = num % 10
     l2dig = ldig % 10
     if l2dig == 1:
         suffix = 'th'
     elif ldig == 1:
         suffix = 'st'
     elif ldig == 2:
         suffix = 'nd'
     elif ldig == 3:
         suffix = 'rd'
     else: 
         suffix = 'th'
     return '%d%s' % (num, suffix)
David Zaslavsky
+7  A: 

Or shorten David's answer with:

if 4 <= day <= 20 or 24 <= day <= 30:
    suffix = "th"
else:
    suffix = ["st", "nd", "rd"][day % 10 - 1]

Attribution.

Abizern
I did not know about the "if x <= y <= z" syntax, couldn't believe it would work and tried it. Looks like I should re-read the Python doc *again* :)
Chris Cameron
That way is kind of hard to generalize though - it gets clunky if you want to use it for arbitrary numbers.
David Zaslavsky
True, but the OP was asking about ordinal dates. Since YAGNI, it would be better to choose the shorter, more elegant solution that meets his needs, even if it's not generalizable. If someone wants a generalized solution, your's is good, though I'd probably use a list rather than the elseifs.
Chris Upchurch
+7  A: 

Here's a more general solution:

def ordinal(n):
    if 10 <= n % 100 < 20:
        return str(n) + 'th'
    else:
       return  str(n) + {1 : 'st', 2 : 'nd', 3 : 'rd'}.get(n % 10, "th")
CTT
A: 

Here it is using dictionaries as either a function or as a lambda...

If you look at the dictionaries backwards you can read it as...

Everything ends in 'th'

...unless it ends in 1, 2, or 3 then it ends in 'st', 'nd', or 'rd'

...unless it ends in 11, 12, or 13 then it ends in 'th, 'th', or 'th'

# as a function
def ordinal(num):
    return '%d%s' % (num, { 11: 'th', 12: 'th', 13: 'th' }.get(num % 100, { 1: 'st',2: 'nd',3: 'rd',}.get(num % 10, 'th')))

# as a lambda
ordinal = lambda num : '%d%s' % (num, { 11: 'th', 12: 'th', 13: 'th' }.get(num % 100, { 1: 'st',2: 'nd',3: 'rd',}.get(num % 10, 'th')))
eric.frederich
A: 

Here is an even shorter general solution:

def foo(n):
    return str(n) + {1: 'st', 2: 'nd', 3: 'rd'}.get(4 if 10 <= n % 100 < 20 else n % 10, "th")

Although the other solutions above are probably easier to understand at first glance, this works just as well while using a bit less code.

deegeedubb