Contents This is a method to convert a natural number of integer type to an ordinal number of string type (0th, 1st, 2nd, 3rd, ..). Here, 0 is also included in the natural number. Each code can be downloaded from the GitHub repository.
Rule Before implementation, first consider the rules by referring to List of notations and readings of English ordinal numbers 1 to 1000.
Code the above rules in order, and finally refactor (organize the code without changing its behavior).
Package to use:
#Standard library
from collections import defaultdict
Execution environment | |
---|---|
OS | Windows Subsystem for Linux |
Python | version 3.8.5 |
Using the collections package defaultdict
[^ 1],
[^ 1]: How to use Python defaultdict
def int2ordinal_1(num):
ordinal_dict = defaultdict(lambda: "th")
suffix = ordinal_dict[num]
return f"{num}{suffix}"
#Indiscriminately"th"return it
print(int2ordinal_1(0))
# -> '0th'
print(int2ordinal_1(1))
# -> '1th':Correspond with rule 2,Correctly 1st'
print(int2ordinal_1(11))
# -> '11th':Correspond with rule 3
Update the dictionary.
ordinal_dict.update({1: "st", 2: "nd", 3: "rd"})
Then change it to determine the ordinal number based on the last digit of the input value.
mod = num % 10
suffix = ordinal_dict[mod]
If you add this to the processing inside the function,
def int2ordinal_2(num):
ordinal_dict = defaultdict(lambda: "th")
ordinal_dict.update({1: "st", 2: "nd", 3: "rd"})
mod = num % 10
suffix = ordinal_dict[mod]
return f"{num}{suffix}"
print(int2ordinal_2(0))
# -> '0th'
print(int2ordinal_2(1))
# -> '1st'
print(int2ordinal_2(11))
# -> '11st':Correspond with rule 3,Correctly 11th'
If you divide by 100 and the remainder is 11, you can return "th", so
if num % 100 == 11:
suffix = "th"
else:
suffix = ordinal_dict[mod]
If you add this to the processing inside the function,
def int2ordinal_3(num):
ordinal_dict = defaultdict(lambda: "th")
ordinal_dict.update({1: "st", 2: "nd", 3: "rd"})
mod = num % 10
if num % 100 == 11:
suffix = "th"
else:
suffix = ordinal_dict[mod]
return f"{num}{suffix}"
print(int2ordinal_3(0))
# -> '0th'
print(int2ordinal_3(1))
# -> '1st'
print(int2ordinal_3(11))
# -> '11th'
It's not a time-consuming process, so it's just a bonus.
num% 100 == 11
is the same as" the remainder when the quotient num // 10
is divided by 10 is 1".
#Change before
mod = num % 10
if num % 100 == 11:
suffix = "th"
else:
suffix = ordinal_dict[mod]
#After change
q = num // 10
mod = num % 10
if q % 10 == 1:
suffix = "th"
else:
suffix = ordinal_dict[mod]
In addition, the quotient and remainder are calculated at once with the divmod
function.
Also, make the if-else statement on one line. This time the effect is weak, but since the number of times to write the algebra suffix
is reduced, typographical errors can be reduced.
q, mod = divmod(num, 10)
suffix = "th" if q % 10 == 1 else ordinal_dict[mod]
If you add this to the processing inside the function,
def int2ordinal_4(num):
ordinal_dict = defaultdict(lambda: "th")
ordinal_dict.update({1: "st", 2: "nd", 3: "rd"})
q, mod = divmod(num, 10)
suffix = "th" if q % 10 == 1 else ordinal_dict[mod]
return f"{num}{suffix}"
print(int2ordinal_4(0))
# -> '0th'
print(int2ordinal_4(1))
# -> '1st'
print(int2ordinal_4(11))
# -> '11th'
It is as follows when the argument type check etc. are added.
ordinal_func.py
def int2ordinal(num):
"""
Convert a natural number to a ordinal number.
Args:
num (int): natural number
Returns:
str: ordinal number, like 0th, 1st, 2nd,...
Notes:
Zero can be used as @num argument.
"""
if not isinstance(num, int):
raise TypeError(
f"@num must be integer, but {num} was applied.")
if num < 0:
raise ValueError(
f"@num must be over 0, but {num} was applied.")
ordinal_dict = defaultdict(lambda: "th")
ordinal_dict.update({1: "st", 2: "nd", 3: "rd"})
q, mod = divmod(num, 10)
suffix = "th" if q % 10 == 1 else ordinal_dict[mod]
return f"{num}{suffix}"
Execution confirmation:
ordinal_func.py
print(int2ordinal(0)) # 0th
print(int2ordinal(1)) # 1st
print(int2ordinal(2)) # 2nd
print(int2ordinal(3)) # 3rd
print(int2ordinal(4)) # 4th
print(int2ordinal(11)) # 11th
print(int2ordinal(21)) # 21st
print(int2ordinal(111)) # 111th
print(int2ordinal(121)) # 121st
I will introduce the method without using defaultdict
, which was commented by @shiracamus.
def int2ordinal_5(num):
ordinal_dict = {1: "st", 2: "nd", 3: "rd"}
q, mod = divmod(num, 10)
suffix = q % 10 != 1 and ordinal_dict.get(mod) or "th"
return f"{num}{suffix}"
print(int2ordinal_5(0))
# -> '0th'
print(int2ordinal_5(1))
# -> '1st'
print(int2ordinal_5(11))
# -> '11th'
num | q | mod | q % 10 != 1 | ordinal_dict.get(mod) | q % 10 != 1 and ordinal_dict.get(mod) | suffix |
---|---|---|---|---|---|---|
0 | 0 | 0 | False | None | False | "th" |
1 | 0 | 1 | True | "st" | "st" | "st" |
11 | 1 | 1 | False | "st" | False | "th" |
Combining the negative form with ʻand` ...
It's hard to come up with this, but it's convenient to use ʻorfor numeric assignments. For example, you can use it when you want to give an empty list of default arguments for a function. (Note that setting
def func (x = []): x.append (0); return x` etc. in the function argument will cause unexpected behavior![^ 2])
[^ 2]: Note that the default value of the [python] argument is evaluation at definition
def func(values=None):
values = values or []
if not isinstance(values, list):
raise TypeError(f"@values must be a list or None, but {values} was applied.")
values.append(0)
return values
If values
is None, False, or empty, the empty list[]
is assigned. Otherwise, the values
argument is used as is.
That's how Python can convert natural numbers to ordinal numbers!
Recommended Posts