Python远程查找表

时间:2012-03-14 01:43:48

标签: python range

我正在尝试创建一种类似于Python中的字典的数据结构,但是使用了远程键。这是场景:

我正在实现一种编程语言,以便与旧游戏向后兼容。游戏中的每条指令都放入一个列表中,并且每次遇到换行符时计数器都会递增。希望如果语言有运行时错误,它将能够查找表中指令的哪一行并将其显示回用户。

因此,如果错误发生在指令20上,而第3行包含指令15-30,则轮询此结构为20应返回3.

拥有一个包含每条指令条目的字典是可能的,但也非常浪费。还有其他方法可以做到吗?

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运行输入