26

I have a list of integers - is there a library to convert them into plain text ranking? IE: 1,2,3 -> "first, second, third" ?

gone
  • 4,342
  • 2
  • 24
  • 29
  • 1
    http://www.daniweb.com/software-development/python/code/216839/number-to-word-converter-python – Ashwini Chaudhary Jun 24 '12 at 20:12
  • 1
    As I started university it was one of our tasks on the first day to write exactly this in Java. If you are somewhat experienced in programming this shouldn't take you longer than 30min. – Lukas Schmelzeisen Jun 24 '12 at 20:36
  • 1
    30 minutes? really lol .. you mean 1 minutes.... http://jsfiddle.net/cmvLS/ (javascript) – ncubica May 24 '13 at 00:30
  • 2
    He isn't asking if this can be coded. He is asking if there is a _pre-existing_ library for it – Anupam Aug 01 '18 at 06:28

7 Answers7

46

The python inflect package has a method for converting numerals into ordinals:

import inflect
p = inflect.engine()

for i in range(1,25,5):
    print(p.ordinal(i))

displays:

1st
6th
11th
16th
21st
psychemedia
  • 5,690
  • 7
  • 52
  • 84
9

How high are you planning on going? (Do you ever expect higher than, say, "twentieth"?)

Maybe you just need a dict,

nth = {
    1: "first",
    2: "second",
    3: "third",
    4: "fourth"
    # etc
}
Tersosauros
  • 883
  • 1
  • 12
  • 22
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
4

can't comment on ryvantage's post because of points but I wrote the same code for python:

def appendInt(num):
    if num > 9:
        secondToLastDigit = str(num)[-2]
        if secondToLastDigit == '1':
            return 'th'
    lastDigit = num % 10
    if (lastDigit == 1):
        return 'st'
    elif (lastDigit == 2):
        return 'nd'
    elif (lastDigit == 3):
        return 'rd'
    else:
        return 'th'



def appendInt2(num):
    value = str(num)
    if len(value) > 1:
        secondToLastDigit = value[-2]
        if secondToLastDigit == '1':
            return 'th'
    lastDigit = value[-1]
    if (lastDigit == '1'):
        return 'st'
    elif (lastDigit == '2'):
        return 'nd'
    elif (lastDigit == '3'):
        return 'rd'
    else:
        return 'th'

The second is more of a direct translation, but I found that the first variation is considerably faster:

Fri Aug 28 11:48:13 2015 results

         300000005 function calls in 151.561 seconds

   Ordered by: call count, name/file/line

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
100000000    6.674    0.000    6.674    0.000 {len}
100000000   43.064    0.000   43.064    0.000 test.py:7(appendInt)
100000000   66.664    0.000   73.339    0.000 test.py:22(appendInt2)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000  151.561  151.561 <string>:1(<module>)
        1    0.000    0.000  151.561  151.561 test.py:51(main)
        1   16.737   16.737   59.801   59.801 test.py:39(test1)
        1   18.421   18.421   91.759   91.759 test.py:45(test2) 
dgonee
  • 91
  • 1
  • 4
4

Similarly to the vein @Hugh Bothwell was following, only not using a dict (since your keys are already nice and numerical), I've put together the following "one liner":

ordinal=lambda x:["first","second","third","fourth","fifth","sixth","seventh","eighth","ninth","tenth","eleventh","twelfth"][x-1]

Which covers all cases up to 12. If you need higher (into the hundreds, etc), then you'll probably need something more robust (with recursion I'd imagine, etc).

Community
  • 1
  • 1
Tersosauros
  • 883
  • 1
  • 12
  • 22
2

Depending on your situation, you might find it useful to retain the integer and append "st", "nd", "rd", and "th". If so, here is a simple algorithm:

NOTE: This algorithm is written in Java. I don't know Python. Anyone who wants to re-write it in Python, be my guest.

public static String appendInt(int number) {
    String value = String.valueOf(number);
    if(value.length() > 1) {
        // Check for special case: 11 - 13 are all "th".
        // So if the second to last digit is 1, it is "th".
        char secondToLastDigit = value.charAt(value.length()-2);
        if(secondToLastDigit == '1')
            return "th";
    }
    char lastDigit = value.charAt(value.length()-1);
    switch(lastDigit) {
        case '1':
            return "st";
        case '2':
            return "nd";
        case '3':
            return "rd";
        default:
            return "th";
    }
}

So

System.out.println(1 + appendInt(1));
System.out.println(2 + appendInt(2));
System.out.println(3 + appendInt(3));
System.out.println(4 + appendInt(4));
System.out.println(5 + appendInt(5));
System.out.println(11 + appendInt(11));
System.out.println(21 + appendInt(21));

displays

1st
2nd
3rd
4th
5th
11th
21st
ryvantage
  • 13,064
  • 15
  • 63
  • 112
0

A nice and simple rewrite:

def num_to_ith(num):
    """1 becomes 1st, 2 becomes 2nd, etc."""
    value             = str(num)
    before_last_digit = value[-2]
    last_digit        = value[-1]
    if len(value) > 1 and before_last_digit == '1': return value +'th'
    if last_digit == '1': return value + 'st'
    if last_digit == '2': return value + 'nd'
    if last_digit == '3': return value + 'rd'
    return value + 'th'
xApple
  • 6,150
  • 9
  • 48
  • 49
-1

My code for this utilizes list, integer modulus to find the first digit and integer floor division to check for off rule 11 thru 13.

    def stringify(number):
        suffix = ["th","st","nd","rd","th","th","th","th","th","th"]
        return str(number) + suffix[number % 10] if str(number // 10)[-1] != 1 else str(number) + "th"        

The last line more readable:

    if str(number // 10)[-1] != '1':     
        return str(number) + suffix[number % 10]
    else:
        return str(number) + "th"

Basically, I'm checking the second digit for 1* which indicates a possible 11th, 12th, 13th rule breaker. For the rule keepers, the list is referenced by the remainder of a divide by 10 (modulus operator).

I haven't done any testing for code efficiency, and checking against length is much more readable, but this works.

*(str(number)[-2] generates an IndexError if the input is a single digit. Using floor division on integers always results in at least 1 digit so the string will always have a -1 index)

Alan Leuthard
  • 798
  • 5
  • 11