Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在5 mb内存和5秒时间的限制下,如何在数组(python)中查找大量的唯一单词?_Python_Python 3.x_Python 3.6 - Fatal编程技术网

在5 mb内存和5秒时间的限制下,如何在数组(python)中查找大量的唯一单词?

在5 mb内存和5秒时间的限制下,如何在数组(python)中查找大量的唯一单词?,python,python-3.x,python-3.6,Python,Python 3.x,Python 3.6,大家好,谁提出了我的问题。我试图解决一个问题,找到大量的独特单词,作为输入输入,第一个输入将是要输入的单词数量。这样地: 五, 跟踪 失落的 鳞片 失落的 桌子 正确答案应该是:4 我尝试用Python解决这个问题,如下所示: a=set() x = int(input()) a.add(x) for i in range(x): y = input() a.add(y) print(len(a)-1) 它似乎工作得很好,只是在内存方面没有效率(在高输入时,它超过了内存限制)。

大家好,谁提出了我的问题。我试图解决一个问题,找到大量的独特单词,作为输入输入,第一个输入将是要输入的单词数量。这样地:
五,
跟踪
失落的
鳞片
失落的
桌子
正确答案应该是:4
我尝试用Python解决这个问题,如下所示:

a=set()
x = int(input())
a.add(x)
for i in range(x):
    y = input()
    a.add(y)
print(len(a)-1)

它似乎工作得很好,只是在内存方面没有效率(在高输入时,它超过了内存限制)。有没有更有效的方法来解决这个问题?

我想到了两个解决方案。第一个是使用JSON结构。JSON结构使用一个唯一的键,然后,您可以创建这个结构,然后检查您有多少个键

代码将如下所示

对于这两个例子,我假设你有一个包含所有单词的数组,这个数组将是
words\u数组

unique_words={}
对于单词数组中的单词:
唯一_单词[word.lower().strip()]=1
#这个可以是任何值
#我只需要创建关键值
打印长度(唯一单词)
我使用了
lower
strip
来确保这个词是唯一的,无论它是大写还是空格

另一种方法是检查数组中是否已经存在单词,这种方法有效,但效率较低

unique_words=[]
对于单词数组中的单词:
w=word.lower().strip()
如果不是w,请使用唯一的单词:
唯一单词。附加(w)
打印长度(唯一单词)

我想如果你在寻找内存效率,我会建议其他替代方法,比如使用C,因为你使用的是Python 3.6+:使用
dict,而不是
集合
。尽管需要为每个元素存储一个值,
dict
s即使在较旧的Python版本中,也经常使用较少的内存(它们针对不同的事情进行了优化;
set
倾向于过度分配存储桶以降低存储桶冲突的风险,但这会消耗更多内存);在3.6+版本中,他们采用了更紧凑的
dict
设计,只要唯一数据不太大,就可以节省更多的数据(当唯一项目的数量超过
2**15
/32768时,
set
s可以在某些尺寸上再次赢得胜利,因为此时紧凑性会显著下降)

因此,要改变它,只需执行以下操作:

a = {}
x = int(input())
for _ in range(x):
    a[input()] = None
print(len(a))
另外,对于速度,如果您不需要使用
输入
,您可能应该避免使用它,直接从
sys.stdin
读取<代码>输入
会对输出进行大量不必要的刷新,以及其他您在此处并不真正需要的工作。因此,这样做可能会更快:

import itertools, sys

x = int(input())
a = dict.fromkeys(itertools.islice(sys.stdin.buffer, x))
print(len(a))
它只需直接拉动线路而不进行修改,并将线路直接推入C级的
dict
,以提高速度。将
sys.stdin
更改为
sys.stdin.buffer
以避免对字符串进行解码,并将
map(str.rstrip,…)
map(bytes.rstrip,…)
包装为
sys.stdin.buffer
以删除换行(如果最后一行可能不以换行结束,这对于正确性是必要的,我想它节省了少量内存)

如果输入可能很大(更高的五位数唯一输入),那么
dict
可能不会有帮助,所以只需坚持使用
set
,但您仍然可以使用
sys.stdin
优化,最终形成如下形式:

x = int(input())
a = set(itertools.islice(map(bytes.rstrip, sys.stdin.buffer), x))
print(len(a))

根据数据的预期性质:

  • 对于字典中的单词,尤其是相似的单词,请使用trie
  • 对于长文本,使用无损压缩
zlib压缩示例:

import zlib

a = set()
x = int(input())
for _ in range(x):
    a.add(zlib.compress(input().encode()))
    #a.add(input())

print("unique: ", len(a))

print("memory: ", sum(len(b) for b in a))
未压缩:

> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique:  2
memory:  32
> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique:  2
memory:  22
压缩:

> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique:  2
memory:  32
> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique:  2
memory:  22

是的,为什么不呢?它是一个集合,所以只存储唯一的单词。最后我计算集合的长度,并减去一个,因为第一次输入(总共的单词数)不应该被计算。为什么还要将从用户处读取的单词数添加到
a
?如果避免这种情况,
len(a)-1
可以缩短为
len(a)
x
无需保存到任何
集合
。同意@DerteTrdelnik-trie将节省大量内存。这是因为,与
集合
不同,trie可以存储例如“水下”和“内衣”,而无需存储两份“内衣”。抱歉,删除了我的评论,因为我看到了另一条关于保留50万字的评论-我不确定询问者是否在某些挑战中使用了正确的工具..因为python在challangesBTW上优化时间和空间时不是最好的,只是为了量化从移动到
字节
:在64位CPython,每个
str
需要额外16个字节的内存(如果空的
str
不是单字节,则需要49个字节,而等效的
bytes
对象需要33个字节,每个额外的字符为每个对象增加一个字节)。如果输入是带有非ASCII字符的
utf-8
编码文本,则成本可能会显著增加(基本开销会增加,对于非拉丁-1字符,每个字符的成本也会增加一倍或四倍)。每个单词
zlib
压缩有助于你传递实际单词的几率基本为零。你构建的假词恰巧压缩得非常好,但英语单词遵循一些已知的模式,而这些模式在给定单词中重复出现的几率足以让
zlib
让你受益基本上是零。trie至少可以提供一些单词间的状态,并可能节省内存;提供一个这样的例子,而不是
zlib
,这基本上保证是无用的。@ShadowRanger同意,对于普通英语单词,我也建议使用trie,但对于随机单词(例如一些生成的ID)或一般文本(t