[英]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.