由this问题的评论提出(我可以看出这是无关紧要的),我现在知道使用字典来查找需要定期查询/访问的数据并不好, speedwise。
我的情况是这样的:
someDict = {}
someDict[(-2, -2)] = something
somedict[(3, -10)] = something else
我将坐标键存储到对象中作为游戏中瓷砖阵列的对象。这些在某些时候会是负面的,所以我不能使用列表或某种稀疏数组(我认为这是术语?)。
我可以:
我会使用一个列表,但是然后查询将从O(log n)变为O(n)以找到(x,y)处的区域。 (我想我的时间也在这里。)
答案 0 :(得分:2)
从
开始加速字典查找,所以这不是问题
字典查找非常快O(1),但是(从你的另一个问题)你不依赖于字典的哈希表查找,你依赖于字典键的线性搜索。
找一些支持稀疏负指数的容器?
这不是索引到字典中。元组是一个不可变对象,你整个都是对元组进行哈希处理。字典真的不知道密钥的内容,只知道它们的哈希值。
我会像其他人一样建议您重组数据。
例如,您可以创建封装所需数据的对象,并将它们排列在二叉树中以进行O(n lg n)次搜索。您甚至可以将整个事物包装在一个类中,它将为您提供所需的if foo in Bar:
语法。
您可能需要一些协调的结构来完成您想要的任务。这是使用dicts和sets的简化示例(稍微调整用户6502的建议)。
# this will be your dict that holds all the data
matrix = {}
# and each of these will be a dict of sets, pointing to coordinates
cols = {}
rows = {}
def add_data(coord, data)
matrix[coord] = data
try:
cols[coord[0]].add(coord)
except KeyError:
# wrap coords in a list to prevent set() from iterating over it
cols[coord[0]] = set([coord])
try:
rows[coord[1]].add(coord)
except KeyError:
rows[coord[1]] = set([coord])
# now you can find all coordinates from a row or column quickly
>>> add_data((2, 7), "foo4")
>>> add_data((2, 5), "foo3")
>>> 2 in cols
True
>>> 5 in rows
True
>>> [matrix[coord] for coord in cols[2]]
['foo4', 'foo3']
现在只需将它包装在一个类或一个模块中,你就会离开,而且一如既往,如果你的猜测不够快,那么你的猜测就不够快。
答案 1 :(得分:2)
Python字典非常快,使用整数元组不会成为问题。但是你的用例似乎有时需要进行单坐标检查,并且遍历所有dict当然很慢。
您可以使用三个词典来加速数据结构以获得所需的访问权限,而不是进行线性搜索:
class Grid(object):
def __init__(self):
self.data = {} # (i, j) -> data
self.cols = {} # i -> set of j
self.rows = {} # j -> set of i
def __getitem__(self, ij):
return self.data[ij]
def __setitem__(self, ij, value):
i, j = ij
self.data[ij] = value
try:
self.cols[i].add(j)
except KeyError:
self.cols[i] = set([j])
try:
self.rows[j].add(i)
except KeyError:
self.rows[j] = add([i])
def getRow(self, i):
return [(i, j, data[(i, j)])
for j in self.cols.get(i, [])]
def getCol(self, j):
return [(i, j, data[(i, j)])
for i in self.rows.get(j, [])]
请注意,还有许多其他可能的数据结构,具体取决于您要执行的操作,读取频率,更新频率,是否通过矩形查询,是否查找最近的非空单元格等等
答案 2 :(得分:1)
另一种选择是简单地改变指数,使其成为正面。
E.g。如果您的指数是连续的,那么:
...
-2 -> a
-1 -> c
0 -> d
1 -> e
2 -> f
...
只需执行LookupArray [Index + MinimumIndex]之类的操作,其中MinimumIndex是您将使用的最小索引的绝对值。
这样,如果您的最小值是-50,那么它将映射到0. -20将映射到30,依此类推。
编辑:
另一种方法是使用如何使用索引的技巧。定义以下关键功能
Key(n) = 2 * n (n >= 0)
Key(n) = -2 * n - 1. (n < 0)
这将所有正键映射到正偶数索引,将所有负数元素映射到正奇数索引。但这可能不实用,因为如果添加100个负键,则必须将数组扩展200个。
还有一点需要注意:如果您打算进行查找并且键的数量是恒定的(或者非常缓慢地变化),请坚持使用数组。否则,词典根本就不好。
答案 3 :(得分:1)
字典查找非常快。搜索密钥的一部分(例如,行x中的所有图块)是不快的。你可以使用dicts的词典。而不是由2元组索引的单个字典,使用这样的嵌套字典:
somedict = {0: {}, 1:{}}
somedict[0][-5] = "thingy"
somedict[1][4] = "bing"
然后,如果你想要给定“行”中的所有图块,它只是somedict[0]
。
您需要一些逻辑来在必要时添加辅助词典等等。提示:在标准getitem()
类型或setdefault()
类型上查看dict
和collections.defaultdict
。
此方法可让您快速访问给定行中的所有切片。如果您想要给定列中的所有切片,它仍然很慢(尽管至少您不需要查看每个单元格,只需查看每一行)。但是,如果需要,您可以通过使用两个dicts(一个在列中,行顺序,另一个在行,列顺序)来解决这个问题。然后更新成为工作量的两倍,这对于大多数磁贴是静态的游戏来说无关紧要,但在任何一个方向上访问都非常容易。
如果您只需要存储数字并且大部分单元格都为0,请查看scipy的稀疏矩阵类。
答案 4 :(得分:0)
使用多维列表 - 通常作为嵌套对象实现。你可以通过一点算术轻松地处理负指数。它可能使用比字典更多的内存,因为某些必须放在每个可能的插槽中(对于空插槽通常为None
),但访问将通过简单的索引查找而不是散列来完成就像用字典一样。