动态查找带循环的序数:find th - st - nd - rd

Find ordinal numbers with loop dynamically: find th - st - nd - rd

我想动态地找到正确的序数根,例如:

111 = 111st
112 = 112nd 
113 = 113rd ...

我尝试了其他解决方案,但找不到合适的解决方案。

这是我的代码:

for number in range(1, 114):
    print(number)
    ex1 = 11
    ex2 = 12
    ex3 = 13
    if number == ex1:
        print("is the " + str(number) + "th number.")
    elif number % 10 == 1 or not ex1:
        print("is the " + str(number) + "st number.")
    elif number == ex2:
        print("is the " + str(number) + "nd number.")
    elif number % 10 == 2 or not ex2:
        print("is the " + str(number) + "nd number.")
    elif number == ex3:
        print("is the " + str(number) + "rd number.")
    elif number % 10 == 3 or not ex3:
        print("is the " + str(number) + "rd number")
    else:
        print("is the " + str(number) + "th number.")

这是一个很好的解决方案:

ordinal = lambda n: "%d%s" % (n, "tsnrhtdd"[(n // 10 % 10 != 1) * (n % 10 < 4) * n % 10::4])


for number in range(1, 114):
    print(f'the {ordinal(number)} number. :) ')

为人类编辑

注意:变量名称不适合在生产环境中使用,我试图更明确地说明 lambda 函数的每个步骤的作用!

def get_ordinal(n):

    hacking_string = "tsnrhtdd"                                # 1)
    is_num_divisible_by_ten = (n // 10 % 10 != 1)              # 2)         
    is_num_reminder_0_3= (n % 10 < 4)                          # 3)
    are_both_false_or_both_true= is_num_divisible_by_ten * is_num_between_0_3  # 4)
    get_index = are_both_false_or_both_true* n % 10  # 5)
    
    return f'{number}{hacking_string[get_index::4]}'  #6)  ---> starts at t | s | n | r
    
for number in range(1, 114):
    print(f'the {get_ordinal(number)} number. :) ')

注意事项

找到的解决方案非常 Hacky 和聪明,我可能永远不会自己想出,正在使用一些聪明的数学技巧来找到数字的偏移集。 然而,根据要求,我简化了函数并添加了一些解释。

  • 步骤 1. 这个字符串最好看成这个 "tsnr" "htdd" |左边是弦的“根”,右边是末尾。 (下面有更多解释)

  • 第 2 步。is_num_divisible_by_ten --> 使用 floor division 结果为 True 或 False。

  • 第3步。is_num_reminder_0_3如果检查N和10的提醒是否在0和3之间,returns一个真/假标志。

  • 步骤 4. are_both_false_or_both_true 乘以 2 bool 值,在 Python True 是 1,False 是 0,所以就像做 --> 1 * 0 . 只有当两个值都为真或都为假时,变量才为真,否则始终为假。

  • 第 5 步。get_index - > Returns 0 or 1 or 2 or 3.

  • 第 6 步。这里是 hacky 部分,使用从 get_index 接收到的索引,是使用 hacking_string 变量和 indexing-and-slicing:

get_index 值始终是以下之一:“tsnr”和采取的步骤 (4) 这些“rhtdd”中的任何一个,因此可能的组合是:

get_index = 0 = "th"  
get_index = 1 = "st"
get_index = 2 = "nd"
get_index = 3 = "rd"

终于

math.stackexchange 上询问其背后的确切数学可能更好,或者如果有人知道添加评论或编辑我的答案会很好!

参考资料(这不是我的解决方案)

指南

你可以这样做:

for number in range(1, 114):
    printedString = str(number)+' is the '+str(number)
    if str(number) == '1' or (str(number)[-1] == '1' and str(number)[-2] != '1'):
        printedString += 'st'
    elif str(number) == '2' or (str(number)[-1] == '2' and str(number)[-2] != '1'):
        printedString += 'nd'
    elif str(number) == '3' or (str(number)[-1] == '3' and str(number)[-2] != '1'):
        printedString += 'rd'
    else:
        printedString += 'th'
    print(printedString+' number.')

所以,问题是 111 显示为 111st 而不是 111th

你有 11 作为 ex1,我假设是“例外 1”的缩写,但你的情况:

if number == ex1:

显然不匹配 111

相反你可以这样做:

if number % 100 == ex1:

对于 11111211 等也是如此

旁注:

elif number % 10 == 1 or not ex1:

显然不是您想要的。这被解释为:

elif (number % 10 == 1) or (not ex1):

not ex1 不依赖于 number 并且总是以相同的方式求值 (False)。但是,由于您已经在单独检查 ex1,因此在此处正确执行此操作是多余的。

如果你想更正它,这样你就不需要检查 ex1 两次,你可以这样做:

if number % 10 == 1 and number % 100 != 11:

我认为在这种情况下使用 !=not 更清楚,我认为将变量分配给 11.

没有任何好处

请注意,11、12 和 13 具有第 th 个后缀。
另请注意,您可以更改 print 函数中的行尾(默认 \n):

print('text', end=' ')
print('another text')

然后,我建议您使用 f"{data} constant text""{} constant text".format(data) 的格式化字符串。

这是我对你的问题的解决方案:

def getSuffix(n):
    if n < 0: raise Exception("Ordinal negative numbers are not allowed")
    if n % 100 in [11, 12, 13]: return 'th'
    if n % 10 == 1: return 'st'
    if n % 10 == 2: return 'nd'
    if n % 10 == 3: return 'rd'
    return 'th'


for number in range(1, 114):
    print(f"{number} is the {number}{getSuffix(number)} number")

希望对您有所帮助。