简体   繁体   English

是否有内置的 Python 函数或模块可以对乘以整数权重的数字求和?

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

What I need to do is take a 10-digit ISBN number and check if it's valid, according to this rule:我需要做的是根据以下规则获取一个 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.根据国际 ISBN 署 2001 年版的官方用户手册,[47] ISBN-10 校验位(即 10 位 ISBN 的最后一位)必须介于 0 到 10 之间(使用符号“X”对于 10),并且必须是十位数字的总和,每个数字乘以其(整数)权重,从 10 到 1,是 11 的倍数。

In other words, if the number is 0-306-40615-2, I need to calculate:换句话说,如果数字是 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

While suggestions or hints on how to write such a function are welcome, my main question is simply whether Python already has a way of doing this, perhaps in the math module.虽然欢迎提供关于如何编写这样一个函数的建议或提示,但我的主要问题只是 Python 是否已经有办法做到这一点,也许在math模块中。

This is my attempt, but the for loops don't work because the inner one keeps starting over.这是我的尝试,但 for 循环不起作用,因为内部循环不断重新开始。 Plus it just seems messy!另外它看起来很乱!

    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```

No, that is way too specific to be something in a standard library.不,这对于标准库中的内容来说太具体了。 It is fairly simple to write though:不过写起来相当简单:

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

I like the comprehension way;我喜欢理解方式; but the imperative way should also work, you just have some logic errors.但是命令式的方式也应该有效,你只是有一些逻辑错误。 In particular, you don't want to iterate all weights for each digit.特别是,您不想迭代每个数字的所有权重。 Each character has exactly one weight if it's a digit, or none if it is not.如果是数字,则每个字符只有一个权重,如果不是,则没有权重。 So an imperative rewrite would be:因此,命令式重写将是:

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

EDIT: various bugs编辑:各种错误

You can use a list comprehension and enunerate() to get the position and value of the first 9 digits.您可以使用列表enunerate()enunerate()来获取前 9 位数字的位置和值。 For each digit, transform the position into its reversed equivalent (10-i) and multiply it by the digit.对于每个数字,将位置转换为其反向等价物(10-i)并将其乘以数字。 If you subtract the sum of these multiplications from 990 you will get a value that will make the total a multiple of 11. The result can then be used as an index in a string containing digits 0 to 9 and letter X:如果从 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"

If the number is 0-306-40615-2, and you need to calculate if如果数字是 0-306-40615-2,你需要计算是否

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

is a multiple of 11 , then you can just write a simple function.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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM