我需要将一个字符串表示为一个数字,但它长度为8928313个字符,注意这个字符串可以包含的不只是字母,而且我必须能够有效地将其转换回来。我当前(太慢)的代码如下所示:
alpha = 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ,.?!@()+-=[]/*1234567890^*{}\'"$\\&#;|%<>:`~_'
alphaLeng = len(alpha)
def letterNumber(letters):
letters = str(letters)
cof = 1
nr = 0
for i in range(len(letters)):
nr += cof*alpha.find(letters[i])
cof *= alphaLeng
print(i,' ',len(letters))
return str(nr)
答案 0 :(得分:2)
好的,因为其他人给出了糟糕的答案,我会介入。
<强>代码强>
def lshift(a, b):
# bitwise left shift 8
return (a << (8 * b))
def string_to_int(data):
sum_ = 0
r = range(len(data)-1, -1, -1)
for a, b in zip(bytearray(data), r):
sum_ += lshift(a, b)
return sum_;
不要这样做
<强>解释强>
字符本质上是字节:它们可以以不同的方式编码,但最终您可以在给定的编码中将它们视为字节序列。为了将它们转换为数字,我们可以将它们向左移8位以获得它们在序列中的位置,从而创建一个唯一的数字。 r
,范围值,是相反顺序的位置:第4个元素需要左边24个字节(3 * 8)等。
获取范围并将数据转换为8位整数后,我们可以转换数据并获取总和,为我们提供唯一标识符。它与原始数字的字节顺序(或反向字节顺序)相同,但只是&#34;作为数字&#34;。这完全是徒劳的。不要这样做。
<强>性能强>
由于您没有正当理由创建相同的对象这一事实将会超过任何性能,但此解决方案具有相当高的性能。
1,000个元素需要~486微秒,10,000个元素需要~20.5毫秒,而100,000个元素需要大约1.5秒。它会起作用,但你不应该这样做。这意味着它被缩放为O(n ** 2),这可能是由于每次整数大小变大时重新分配数据的内存开销。这可能需要约4个小时来处理所有8e6元素(14365秒,计算出将低阶数据拟合到ax**2+bx+c
)。请记住,这是为了获得与原始数据相同的字节表示。
<强>无用强>
请记住,根据目前的估计,整个宇宙中有~1e78到1e82个原子。这是~2 ^ 275。您的值将能够代表2 ^ 71426504,或者代表宇宙中每个原子所需的位数的约260,000倍。你不需要这样的号码。你永远不会。
答案 1 :(得分:1)
如果只有ANSII字符。您可以使用ord()
和chr()
。
答案 2 :(得分:0)
您可以执行多项优化。例如,find
方法需要在字符串中搜索相应的字母。字典会更快。更快的可能是(基准!)chr
函数(如果你对字母排序不太挑剔)和ord
函数来反转chr
。但是如果你对排序没有挑剔的话,如果你只是留下NULL-padded你的字符串并在内存中将其视为一个大的二进制数字,如果你不需要在任何地方显示值,那可能会更好特殊格式。
您可以通过迭代字符而不是字符索引来获得一些加速。如果你正在使用Python 2,那么大的range
会很慢,因为需要生成一个列表(使用xrange
而不是Python 2); Python 3使用了一个生成器,所以它更好。
你的print
功能会减慢输出速度,特别是如果你输出到tty。
大量图书馆也可能会为您加速:Handling big numbers in code
答案 3 :(得分:0)
您的alpha.find()
函数需要在每个循环中迭代alpha
。
你可以使用dict
加快速度,因为字典查找是O(1):
alpha = 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ,.?!@()+-=[]/*1234567890^*{}\'"$\\&#;|%<>:`~_'
alpha_dict = { letter: index for index, letter in enumerate(alpha)}
print(alpha.find('$'))
# 83
print(alpha_dict['$'])
# 83