是否有内置的 Python 函数或模块可以将数字乘以其整数权重相加?

Is there a built-in Python function or module that will sum digits multiplied by their integer weight?

我需要做的是取一个 10 位的 ISBN 号并根据这个规则检查它是否有效:

According to the 2001 edition of the International ISBN Agency's official user manual,[47] the ISBN-10 check digit (which is the last digit of the 10-digit ISBN) must range from 0 to 10 (the symbol 'X' is used for 10), and must be such that the sum of the ten digits, each multiplied by its (integer) weight, descending from 10 to 1, is a multiple of 11.

也就是说,如果数字是0-306-40615-2,我需要计算:

(0 * 10) + (3 * 9) + (0 * 8) + (6 * 7) + (4 * 6) + (0 * 5) + (6 * 4) + (1 * 3) + (5 * 2) + (2 * 1) mod 11

虽然欢迎提供有关如何编写此类函数的建议或提示,但我的主要问题只是 Python 是否已经有这样做的方法,也许在 math 模块中。

这是我的尝试,但是 for 循环不起作用,因为内部循环一直在重新开始。而且它看起来很乱!

    checksum = 0
    for digit in isbn:
        for weight in range(10, 0, -1):
            if digit == 'X':
                checksum += 10 * weight
                break
            checksum += int(digit) * weight
            break
    return checksum % 11```

不,这太具体了,无法成为标准库中的内容。不过写起来相当简单:

def check_isbn(isbn):
    isbn_digits = (
        10 if ch == 'X' else int(ch)
        for ch in isbn
        if ch.isdigit() or ch == 'X')

    checksum = sum(
        (10 - index) * digit
        for index, digit
        in enumerate(isbn_digits)
    ) % 11

    return checksum % 11 == 0

我喜欢理解的方式;但命令式的方式也应该有效,你只是有一些逻辑错误。特别是,您不想迭代每个数字的所有权重。如果是数字,每个字符只有一个权重,如果不是,则为 none。因此,命令式重写将是:

def check_isbn(isbn):
    checksum = 0
    weight = 10
    for ch in isbn:
        if ch == 'X':
            digit = 10
        elif ch.isdigit():
            digit = int(ch)
        else:
            continue
        checksum += digit * weight
        weight -= 1

    return checksum % 11 == 0

编辑:各种错误

如果号码是0-306-40615-2,需要计算if

(0 * 10) + (3 * 9) + (0 * 8) + (6 * 7) + (4 * 6) + (0 * 5) + (6 * 4) + (1 * 3) + (5 * 2) + (2 * 1)

是11的倍数,那你写一个简单的函数就可以了。

def check_isbn(isbn): #isbn should be type str
    isbn = "".join(isbn.split("-"))
    sum = (int(isbn[0]) * 10) + (int(isbn[1]) * 9) + (int(isbn[2]) * 8) + (int(isbn[3]) * 7) + (int(isbn[4]) * 6) + (int(isbn[5]) * 5) + (int(isbn[6]) * 4) + (int(isbn[7]) * 3) + (int(isbn[8]) * 2) + (int(isbn[9]) * 1)
    return sum % 11 == 0

check_isbn("1416406110")
# False

check_isbn("0-306-40615-2")
# True

您可以使用列表理解和 enunerate() 来获取前 9 位数字的位置和值。对于每个数字,将位置转换为其反向等效 (10-i) 并将其乘以数字。如果从 990 中减去这些乘法的总和,您将得到一个值,该值将使总和成为 11 的倍数。结果可以用作包含数字 0 到 9 和字母 X 的字符串中的索引:

isbn     = "0-306-40615-2"
numbers  = [int(n) for n in isbn if n.isdigit()]
check    = "0123456789X"[ (990-sum(n*(10-i) for i,n in enumerate(numbers[:9])))%11]
isValid  = isbn[-1] == check  

print(check) # "2"