将整数分解为数字以计算ISBN校验和

57

我正在编写一个计算ISBN号码校验位的程序。我需要将用户输入的ISBN的前九位读入一个整数变量中,然后将最后一位乘以2,倒数第二位乘以3,以此类推。如何将整数“拆分”成其组成数字?由于这是一个基本的作业练习,我不应该使用列表。

15个回答

89

将其转换为字符串即可。

myinteger = 212345
number_string = str(myinteger)

好的,现在您可以对其进行迭代:

for ch in number_string:
    print ch # will print each digit in order

或者你可以使用切片:

print number_string[:2] # first two digits
print number_string[-3:] # last three digits
print number_string[3] # forth digit
或者更好的做法是,不要将用户的输入转换为整数(用户输入的是字符串)。
isbn = raw_input()
for pos, ch in enumerate(reversed(isbn)):
    print "%d * %d is %d" % pos + 2, int(ch), int(ch) * (pos + 2)

想要了解更多信息,请阅读教程


这太棒了。谢谢! - LucCW
@nosklo 很抱歉,教程链接已经失效了。你介意编辑一下吗? - M.A.K. Simanto
当您打印数字时,会在开头多出一个1,我该如何解决? - Pooya Panahandeh

77
while number:
    digit = number % 10

    # do whatever with digit

    # remove last digit from number (as integer)
    number //= 10

在每次循环中,它会从数字中移除最后一位,并将其赋值给digit。 它是反向的,从最后一位开始,以第一位结束。


我添加了一个解释。如果你不明白它是如何工作的,拿一张纸,按照选择的步骤逐步进行。 - Alexandru Nedelcu
它从给定的数字中提取数字,假设基数为10,从最低有效数字开始。这是一种数学方法,而不是Pythonic方法。这是一种适用于任何语言的方法。并且当人们对以另一种基数编写的数字的数字感兴趣时,这种方法也可以使用(与此处发布的其他解决方案不同)。因此:+1。 - Stephan202
2
为什么不使用生成器?yield digit - st0le
4
+1,因为这比转换为字符串快2-3倍。 - bpgergo
3
我无法相信人们不认识到这个解决方案的实用性。 - franklin
显示剩余4条评论

23
list_of_ints = [int(i) for i in str(ISBN)]

这将为您提供一个有序的整数列表。当然,根据鸭子类型,您也可以使用str(ISBN)来处理。

编辑:如评论中所述,该列表没有按升序或降序排序,但它确实有一个定义好的顺序(在Python中集合,字典等理论上没有顺序,尽管在实践中顺序倾向于相对可靠)。如果您想要对其进行排序:

list_of_ints.sort()

是您的好朋友。请注意,sort()就地排序(即实际更改现有列表的顺序),不返回新列表。


4
list_of_ints = map(int, str(ISBN)) - uolot
耶,棒极了!让我们不要忘记 map/reduce/zip 等等! - Daren Thomas
“排序的整数列表”?它将以什么意义上的“排序”呈现? - SilentGhost
@Daren - 不一定更快,但通常更易读(不包括 reduce() ^^) - uolot
按照定义的顺序排序,与元组或集合不同。我将把它编辑到答案中... - mavnn
是的,我提交后就意识到了。你会注意到我在编辑中没有提到它们。 - mavnn

14

在旧版本的Python中...

map(int,str(123))

在新版本3k上

list(map(int,str(123)))

@Lord British,很难说,因为两者都是为不同版本设计的,我想Py3k应该会更快(希望如此,呵呵)。 - st0le

4
(number/10**x)%10

你可以在循环中使用它,其中 number 是完整的数字,x 是循环的每个迭代(0,1,2,3,...,n),n 是终止点。 x = 0 给出个位数,x = 1 给出十位数,x = 2 给出百位数,以此类推。请记住,这将从右到左给出数字的值,因此这可能不适用于 ISBN,但仍会隔离每个数字。

2

将其转换为字符串,并使用int()函数进行映射。

map(int, str(1231231231))

2

将数据转换为str比除以10要慢。

map比列表推导稍微慢一些:

convert to string with map 2.13599181175
convert to string with list comprehension 1.92812991142
modulo, division, recursive 0.948769807816
modulo, division 0.699964046478

以下代码在我的笔记本电脑上返回了这些时间:
foo = """\
def foo(limit):
    return sorted(set(map(sum, map(lambda x: map(int, list(str(x))), map(lambda x: x * 9, range(limit))))))

foo(%i)
"""

bar = """\
def bar(limit):
    return sorted(set([sum([int(i) for i in str(n)]) for n in [k *9 for k in range(limit)]]))

bar(%i)
"""

rac = """\
def digits(n):
    return [n] if n<10 else digits(n / 10)+[n %% 10]

def rabbit(limit):
    return sorted(set([sum(digits(n)) for n in [k *9 for k in range(limit)]]))

rabbit(%i)
"""

rab = """\
def sum_digits(number):
  result = 0
  while number:
    digit = number %% 10
    result += digit
    number /= 10
  return result

def rabbit(limit):
    return sorted(set([sum_digits(n) for n in [k *9 for k in range(limit)]]))

rabbit(%i)
"""


import timeit

print "convert to string with map", timeit.timeit(foo % 100, number=10000)
print "convert to string with list comprehension", timeit.timeit(bar % 100, number=10000)
print "modulo, division, recursive", timeit.timeit(rac % 100, number=10000)
print "modulo, division", timeit.timeit(rab % 100, number=10000)

2

递归版本:

def int_digits(n):
    return [n] if n<10 else int_digits(n/10)+[n%10]

2

经过自己的努力搜索,我找到了几个解决方案,每个方案都有优缺点。请选择最适合您任务的方案。

所有示例均在GNU/Linux Debian 8操作系统上使用CPython 3.5进行测试。


使用递归

代码:

def get_digits_from_left_to_right(number, lst=None):
    """Return digits of an integer excluding the sign."""

    if lst is None:
        lst = list()

    number = abs(number)

    if number < 10:
        lst.append(number)
        return tuple(lst)

    get_digits_from_left_to_right(number // 10, lst)
    lst.append(number % 10)

    return tuple(lst)

演示

In [121]: get_digits_from_left_to_right(-64517643246567536423)
Out[121]: (6, 4, 5, 1, 7, 6, 4, 3, 2, 4, 6, 5, 6, 7, 5, 3, 6, 4, 2, 3)

In [122]: get_digits_from_left_to_right(0)
Out[122]: (0,)

In [123]: get_digits_from_left_to_right(123012312312321312312312)
Out[123]: (1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 1, 3, 1, 2, 3, 1, 2, 3, 1, 2)

使用函数 divmod

代码

def get_digits_from_right_to_left(number):
    """Return digits of an integer excluding the sign."""

    number = abs(number)

    if number < 10:
        return (number, )

    lst = list()

    while number:
        number, digit = divmod(number, 10)
        lst.insert(0, digit)

    return tuple(lst)

演示

In [125]: get_digits_from_right_to_left(-3245214012321021213)
Out[125]: (3, 2, 4, 5, 2, 1, 4, 0, 1, 2, 3, 2, 1, 0, 2, 1, 2, 1, 3)

In [126]: get_digits_from_right_to_left(0)
Out[126]: (0,)

In [127]: get_digits_from_right_to_left(9999999999999999)
Out[127]: (9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9)

使用构造函数 tuple(map(int, str(abs(number)))

In [109]: tuple(map(int, str(abs(-123123123))))
Out[109]: (1, 2, 3, 1, 2, 3, 1, 2, 3)

In [110]: tuple(map(int, str(abs(1412421321312))))
Out[110]: (1, 4, 1, 2, 4, 2, 1, 3, 2, 1, 3, 1, 2)

In [111]: tuple(map(int, str(abs(0))))
Out[111]: (0,)

使用函数re.findall 该函数用于在字符串中查找所有匹配正则表达式的子串。
In [112]: tuple(map(int, re.findall(r'\d', str(1321321312))))
Out[112]: (1, 3, 2, 1, 3, 2, 1, 3, 1, 2)

In [113]: tuple(map(int, re.findall(r'\d', str(-1321321312))))
Out[113]: (1, 3, 2, 1, 3, 2, 1, 3, 1, 2)

In [114]: tuple(map(int, re.findall(r'\d', str(0))))
Out[114]: (0,)

Using the module decimal

In [117]: decimal.Decimal(0).as_tuple().digits
Out[117]: (0,)

In [118]: decimal.Decimal(3441120391321).as_tuple().digits
Out[118]: (3, 4, 4, 1, 1, 2, 0, 3, 9, 1, 3, 2, 1)

In [119]: decimal.Decimal(-3441120391321).as_tuple().digits
Out[119]: (3, 4, 4, 1, 1, 2, 0, 3, 9, 1, 3, 2, 1)

1
this的答案类似,更“Pythonic”的方法是迭代数字的方式:
while number:
    # "pop" the rightmost digit
    number, digit = divmod(number, 10)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接