我正在尝试创建一种类似于Python中的字典的数据结构,但是使用了远程键。这是场景:
我正在实现一种编程语言,以便与旧游戏向后兼容。游戏中的每条指令都放入一个列表中,并且每次遇到换行符时计数器都会递增。希望如果语言有运行时错误,它将能够查找表中指令的哪一行并将其显示回用户。
因此,如果错误发生在指令20上,而第3行包含指令15-30,则轮询此结构为20应返回3.
拥有一个包含每条指令条目的字典是可能的,但也非常浪费。还有其他方法可以做到吗?
答案 0 :(得分:3)
根据你的描述,你有一个单调递增的计数器和一个形式的地图函数(例如下面的常量):
0 <= x < 5: 0
5 <= x < 7: 1
7 <= x < 10: 2
10 <= x < 18: 3
18 <= x < 21: 4
似乎转换点的简单数组(在Python中为list)就足够了:
[5, 7, 10, 18, 21]
然后给出x,你找到i的最小值,使得arr [i]&gt; = x。
您可以通过内插搜索找到该索引,该搜索大致为O(log log n),其中n是数组的长度(代码留作练习:-))。
答案 1 :(得分:2)
“拥有一个包含每条指令条目的字典是可能的,但也非常浪费。”您是否期望用该语言编写的程序长达数百万条指令?如果没有,这正是我推荐的。不要过早优化。大多数人将此格言解释为表示性能,但它也适用于资源使用。
如果您确实需要优化空间,假设您使用的是Python 2.6或更高版本,我推荐的是bytearray
。顾名思义,它是一个字节数组,因此可以表示0-255的值。数组中的每个项目都代表相应行上的语句数。要将指令编号转换回行号,可能是这样的:
instcounts = bytearray((2, 4, 6, 3, 1, 1, 5, 2, 3))
def getline(instnumber):
count = line = 0
while count <= instnumber and line < len(instcounts):
count += instcounts[line]
line += 1
return line # conveniently, this will be 1-indexed :-)
getline(15) # tells me instruction 15 is on line 5
这比torek的答案更有优势的是它每行源代码只存储一个字节的相同信息:很多比列表更有效。你需要做一些额外的工作来弄清楚行号,但实际上你甚至不会注意到非常大的文件,你只会在打印错误信息时运行它,而不是速度关键的功能。上面的函数在代表1,000,000行的bytearray
上大约需要十分之一秒,而在运行于4年前Mac Pro上的Windows XP VM上,这是Python 3.1下的未经优化的代码。
需要内存吗? 1,087,199字节,大约是forrek解决方案中仅用于列表所需的四分之一 - 不包括列表中引用的int
个对象,每个对象为14个字节(CPython)但是,重用一个小整数对象池,如果整数有额外的内存,那么小文件可能用得不多。)
顺便说一句,CPython使用了一个非常相似的方案(在任何函数上看func_code.co_lnotab
或__code__.co_lnotab
)。
答案 2 :(得分:0)
这是一个调整dict键的类:
class rdict(dict):
def __init__(self, incSize, *args):
self.incSize = incSize
dict.__init__(self, *args)
def __normRange(self, keyArg, incSize):
return keyArg // incSize * incSize
def __getitem__(self, key):
return dict.__getitem__(self, self.__normRange(key, self.incSize))
def __setitem__(self, key, value):
dict.__setitem__(self, self.__normRange(key, self.incSize), value)
g = input("hi")
d = rdict(3)
d[10.4] = "a"
print d
输出: {9.0:“a”}
如果您不打算使用它,请忘记课程,只需通过函数normRange运行输入