Python 如何从1m字符串输入中计算唯一值?
我在我的大学里有一项任务,但仍然得不到。 输入时,我有几个加速:Python 如何从1m字符串输入中计算唯一值?,python,arrays,performance,numpy,Python,Arrays,Performance,Numpy,我在我的大学里有一项任务,但仍然得不到。 输入时,我有几个加速: );它将避免在每个循环中制造不同的整数对象 将名称s_add绑定到s.add以便在紧密绑定的循环中更快地查找:s=set();s_add=s.add,然后在循环中调用s_add(x)* *如果内存允许的话,Python 3的最新版本在最小化属性查找差异方面做得更好。这可能是一个可疑的增量效益,但试一试 关于散列-两个常见的选项是Md5和Sha1,它们分别产生16字节和20字节的散列字节对象。至少在我的笔记本电脑上,Sha1的速度更
s_add
绑定到s.add
以便在紧密绑定的循环中更快地查找:s=set();s_add=s.add
,然后在循环中调用s_add(x)
*字节对象。至少在我的笔记本电脑上,Sha1的速度更快,但不是一吨:
>>> import hashlib
>>> import string
>>> import random
>>> b = bytes(
... "".join(random.choices(string.ascii_letters, k=999)),
... 'utf-8'
... )
>>> %timeit hashlib.md5(b).digest()
2.48 µs ± 8.62 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit hashlib.sha1(b).digest()
1.96 µs ± 6.12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
但你可能不需要这么重的东西。(您对散列不感兴趣是因为它的加密安全性;您对它感兴趣是为了节省累积集中的空间。)还有内置的hash()
,尽管不能保证在Python会话中对相同的输入是相同的,这似乎不是一个要求,因为您正在处理来自单个进程的字符串:
>>> %timeit hash(b)
84.9 ns ± 0.193 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
作为免责声明,我对hash()
的实现及其产生的熵不太熟悉(好吧,一点也不熟悉)。[一些阅读。)我敢说碰撞的概率在数学上比Md5+Sha1要高,尽管可能仍然非常非常低。我一直非常感兴趣地关注,并建议(要归功于@Brad Solomon)
导入hashlib
进口itertools
N=int(输入())
s=集合()
s_add=s.add
对于itertools中的uu。重复(无,N):
s_add(hashlib.md5(input().encode()).hexdigest()[:-3])
印刷品(透镜)
(这实际上并不是仅仅通过使用numpy lib实现的。)
编辑这样
N=int(输入())
s=集合()
s_add=s.add
对于范围(N)中的i:
添加(输入()[:-300])
印刷品(透镜)
您可能有一个千兆字节的输入数据(如果它的长度最大,并且每个字符串的长度最大)-很明显,您无法将所有字符串存储在5 MB中。除非您做出一些假设,但您没有告诉我们,否则问题似乎无法解决。如果保证字符串在前几个字符中是唯一的,您可以存储每个字符串最多5个字符的前缀-我想这就是dtype='s5'代码>以numpy术语表示。或者,如果你能容忍哈希冲突的可能性,你可以存储每个字符串的32位哈希。@jasonharper我同意这似乎不太可能。从描述和代码中我看到一个小机会,可能一次只读取一个项。在这种情况下,我会完全跳过numpy,使用内置类。仅限Setsy允许唯一项,查找操作在固定时间内完成。如果没有关于输入的更多细节,我不能说这是否可以解决。@G.Anderson唯一的问题是指定使用numpy有问题。否则是的,只需执行len(set(L))
是我的直接想法。@Andy fair point,但一般来说,当应用这样的限制时,“您只能使用标准库和numpy”,因为否则他们将不得不重新发明轮子w.r.t.输入和for循环。set()
不需要任何额外的导入,因此这对OP来说确实是一个很好的澄清:是要求您只在numpy中完成所有工作,还是不允许在numpy之外使用额外的导入LIB?等等,根据问题中的新细节,测试#8成功了:您需要在5秒和5MB RAM的5%以内,并且测试#8在4%以内。谢谢。大约2)-我更改了时间和内存。我已更新:itertools。重复(无,N)
占用了更多内存:(如果您减少当前哈希中的位,并尝试将范围(N)中的I的改为范围(N)中的
。现在只需要减少0.15Mb!我相信成功的关键是接受5%的失败率,并且只存储要设置()的最小数据量。因此,如果我们使用TEST3并将其更改为“s_add(input[:-50])”,我们可能会进一步降低RAM使用率。或者使用TEST8并在哈希中仅存储95%的值。
N = int(input())
a = np.array([])
cc = 0
for i in range(N):
x = input()
cc += 1
if cc < 500:
if not np.any(a == x):
a = np.append(a, x)
print(len(a))
N = int(input())
s = set()
for i in range(N):
x = input()
s.add(x)
print(len(s))
import hashlib
N = int(input())
s = set()
for i in range(N):
x = input()
s.add(hashlib.md5(x.encode()).hexdigest())
print(len(s))
import hashlib
N = int(input())
s = set()
s_add = s.add
for i in range(N):
s_add(hashlib.md5(input().encode()).hexdigest()[:-3])
print(len(s))
import hashlib
import itertools
N = int(input())
s = set()
s_add = s.add
for _ in itertools.repeat(None, N):
s_add(str(abs(hash(input())))[:-3])
print(len(s))
import itertools
N = int(input())
s = set()
s_add = s.add
for _ in itertools.repeat(None, N):
s_add(abs(hash(input())))
print(len(s))
N = int(input())
s = set()
s_add = s.add
for i in range(N):
s_add(abs(hash(input())))
print(len(s))
>>> import hashlib
>>> import string
>>> import random
>>> b = bytes(
... "".join(random.choices(string.ascii_letters, k=999)),
... 'utf-8'
... )
>>> %timeit hashlib.md5(b).digest()
2.48 µs ± 8.62 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit hashlib.sha1(b).digest()
1.96 µs ± 6.12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> %timeit hash(b)
84.9 ns ± 0.193 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)