繁体   English   中英

具有 0-9 和 AZ 的 Python 序列号生成器

[英]Python sequential number generator with 0-9 and A-Z

我正在尝试完成一个数字生成器,它递增数字(0-9)和字符(AZ 不区分大小写),以便在我们的软件项目中唯一标识某些对象。 输出字符串的长度应为 14。

生成器应该能够创建一系列序列号/字符(参见下面的示例),这些序列号/字符将用于运行一些带有数据库的 python 应用程序的潜在数百台设备。 我们希望实现以下逻辑并将这些序列号范围“提供”给设备,因此我们确保我们在所有系统中都有唯一的 ID。 我们更喜欢这种逻辑而不是经典的随机 id 创建。

增量应该从右到左开始。 数字以 0-9 开头。 如果达到 9,则索引应从 AZ 开始递增。 如果达到 Z,则左侧索引号应从 0 增加到 1 或 9 => AZ(高一)。 然后,正确的索引应该再次以相同的逻辑递增,从 0 => 1-9 开始,然后是 AZ。

一些示例输出:

  • 00000000000009
  • 0000000000000A
  • 0000000000000B

或者:

  • 0000000000000Z
  • 00000000000010
  • 00000000000011

等等。

该函数还应该能够以给定的数字开始,例如 00000000005X ,然后以 00000000005Y 等继续。

如何在 Python 中构建它?

您可以使用string模块中的常量来获取所有数字/大写 ASCII 字符,然后使用itertools.product生成 ID:

import string
import itertools

# Create the iterable.
characters = string.digits + string.ascii_uppercase
n = 14
id_iterable = map(''.join, itertools.product(characters, repeat=n))

# Get the first 50 elements in the iterable and print them out (for demo purposes).
head = list(itertools.islice(id_iterable, 50))
print(*head, sep='\n')

这输出:

00000000000000
00000000000001
00000000000002
00000000000003
00000000000004
00000000000005
00000000000006
00000000000007
00000000000008
00000000000009
0000000000000A
0000000000000B
0000000000000C
0000000000000D
0000000000000E
0000000000000F
0000000000000G
0000000000000H
0000000000000I
0000000000000J
0000000000000K
0000000000000L
0000000000000M
0000000000000N
0000000000000O
0000000000000P
0000000000000Q
0000000000000R
0000000000000S
0000000000000T
0000000000000U
0000000000000V
0000000000000W
0000000000000X
0000000000000Y
0000000000000Z
00000000000010
00000000000011
00000000000012
00000000000013
00000000000014
00000000000015
00000000000016
00000000000017
00000000000018
00000000000019
0000000000001A
0000000000001B
0000000000001C
0000000000001D

你可以试试:

import numpy as np

def f(start):
    n = int(start, base=36)
    while True:
        yield np.base_repr(n, 36).rjust(14,"0")
        n += 1

然后:

g = f('0000000000012S')

for i in range(10):
    print(next(g))

它给:

0000000000012S
0000000000012T
0000000000012U
0000000000012V
0000000000012W
0000000000012X
0000000000012Y
0000000000012Z
00000000000130
00000000000131

该程序仅使用string模块,而不是itertools我还添加了名为LENGTHSTART的常量,您可以更改它们

代码:

from string import ascii_uppercase

sequence = [str(i) for i in range(10)] + list(ascii_uppercase)

LENGTH = 14
START = '0' * LENGTH

last = list(START)
while last != list('Z' * LENGTH):
    print(''.join(last))
    i = 1
    while last[-i] == 'Z':
        last[-i] = '0'
        i += 1
    last = last[:-i] + [sequence[sequence.index(last[-i]) + 1]] + last[LENGTH-i+1:]

输出:

00000000000000 
00000000000001 
00000000000002 
00000000000003 
00000000000004 
00000000000005 
00000000000006 
00000000000007 
00000000000008 
00000000000009 
0000000000000A 
0000000000000B 
0000000000000C 
0000000000000D 
0000000000000E 
0000000000000F 
0000000000000G 
0000000000000H 
0000000000000I 
0000000000000J 
0000000000000K 
0000000000000L 
0000000000000M 
0000000000000N 
0000000000000O 
0000000000000P 
0000000000000Q 
0000000000000R 
0000000000000S 
0000000000000T 
0000000000000U 
0000000000000V 
0000000000000W 
0000000000000X 
0000000000000Y 
0000000000000Z 
00000000000010 
00000000000011 
00000000000012 
00000000000013 
00000000000014 
00000000000015 
00000000000016 
00000000000017 
00000000000018 
00000000000019 
0000000000001A 
0000000000001B 
0000000000001C 
0000000000001D 
0000000000001E 
0000000000001F 
0000000000001G
...

正在使用您的问题作为练习,看看我是否可以在 JS 中快速实现该算法,并不打算提供解决方案,因为我预计这个“家庭作业式”问题会很快得到答案。 @bb1 的 numpy 解决方案似乎相当不错,itertools 方法也是如此(尽管它实际上并未编写为生成器函数)。 虽然两者都有图书馆开销。

有点惊讶没有一个好的算法方法,只有图书馆的答案。 所以我想我会分享我的,即使它是用错误的语言。 在 Python 中采用这个应该不会太棘手,除了可能将 JS 闭包转换为 Python 中的生成器函数。 如本文所述,如果我们碰巧点击“ZZZZZZZZZZZZZZ”,则生成的下一个值是“00000000000000”,然后我们重新启动。

function GetGenerator(start_val) {
    
    const min_val = "0"
    const id_len = 14;
    
    if (start_val && start_val.length != id_len) 
        throw "Initial value length isn't " + id_len
    
    // A dictionary mapping each character to the next & 'Z' to 'undefined'
    const incrementer = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
        .reduce((acc, cur, idx, arr) => (acc[cur] = arr[idx+1], acc), {})
    
    const counter = start_val ? start_val.split("") : Array(id_len).fill(min_val)
    
    function increment() {
        //  Moving backwards through the array  <--
        // ["0", "0", "0", "0", ... , "0", "5", "X" ]
        for(let i = id_len - 1; i >= 0; i--) {
            const next = incrementer[counter[i]]
            if (next) {
                counter[i] = next
                return
            } else {
                counter[i] = min_val
                // No return, it's a carry. Increment the next index.
            }                
        }
    }
    
    return function gen() {
        increment()
        return counter.join("")
    }
}

像这样使用:

const generator = GetGenerator("0000000000005X")

generator()
>>> "0000000000005Y"
generator()
>>> "0000000000005Z"
generator()
>>> "00000000000060"

暂无
暂无

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

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