我最近正在处理的一个代码被发现使用了大约200MB的内存来运行,我很困惑为什么它需要那么多。
基本上,它将一个文本文件映射到一个列表中,其中文件中的每个字符都是它自己的包含该字符的列表,以及到目前为止(从零开始)作为它的两个项目出现的频率。
所以'abbac...'会[['a','0'],['b','0'],['b','1'],['a','1'],['c','0'],...]
对于 100 万个字符长的文本文件,它使用了 200MB。
这是合理的还是我的代码正在做的其他事情?如果合理,是因为列表数量多吗?会[a,0,b,0,b,1,a,1,c,0...]占用更少的空间吗?
如果您不需要列表本身,那么我完全订阅@Lattyware 使用生成器的解决方案。
但是,如果这不是一个选项,那么也许您可以通过仅存储文件中每个字符的位置来压缩列表中的数据而不会丢失信息。
import random
import string
def track_char(s):
# Make sure all characters have the same case
s = s.lower()
d = dict((k, []) for k in set(s))
for position, char in enumerate(s):
d[char].append(position)
return d
st = ''.join(random.choice(string.ascii_uppercase) for _ in range(50000))
d = track_char(st)
len(d["a"])
# Total number of occurrences of character 2
for char, vals in d.items():
if 2 in vals:
print("Character %s has %s occurrences" % (char,len(d[char]))
Character C has 1878 occurrences
# Number of occurrences of character 2 so far
for char, vals in d.items():
if 2 in vals:
print("Character %s has %s occurrences so far" % (char, len([x for x in d[char] if x <= 2))
Character C has 1 occurrences so far
Run Code Online (Sandbox Code Playgroud)
这样就不需要每次出现时都重复字符串,并且您可以维护所有出现的信息。
要比较原始列表或此方法的对象大小,这里有一个测试
import random
import string
from sys import getsizeof
# random generation of a string with 50k characters
st = ''.join(random.choice(string.ascii_uppercase) for _ in range(50000))
# Function that returns the original list for this string
def original_track(s):
l = []
for position, char in enumerate(s):
l.append([char, position])
return l
# Testing sizes
original_list = original_track(st)
dict_format = track_char(st)
getsizeof(original_list)
406496
getsizeof(dict_format)
1632
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,dict_format 的大小大约小了 250 倍。然而,这种大小差异在较大的字符串中应该更加明显。