I have a list of integers - is there a library to convert them into plain text ranking? IE: 1,2,3 -> "first, second, third" ?
-
1http://www.daniweb.com/software-development/python/code/216839/number-to-word-converter-python – Ashwini Chaudhary Jun 24 '12 at 20:12
-
1As 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
-
130 minutes? really lol .. you mean 1 minutes.... http://jsfiddle.net/cmvLS/ (javascript) – ncubica May 24 '13 at 00:30
-
2He 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 Answers
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

- 5,690
- 7
- 52
- 84
-
1
-
-
11`p.number_to_words(p.ordinal(i))` will display it as `first`, `second`, `third`, etc. – Nikolay Vyahhi Mar 08 '18 at 13:09
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
}

- 883
- 1
- 12
- 22

- 55,315
- 8
- 84
- 99
-
4
-
1for smaller lists, this is a great answer. _Readability_ is sometimes more important than other things – Anupam Aug 01 '18 at 06:09
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)

- 91
- 1
- 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).

- 1
- 1

- 883
- 1
- 12
- 22
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

- 13,064
- 15
- 63
- 112
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'

- 6,150
- 9
- 48
- 49
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)

- 798
- 5
- 11