python - 字典Python的智能循环

标签 python dictionary optimization

我的字典看起来像

position_dictionnary = {(0,0): <PositionObject1>, (0,1): <PositionObject2>, ...  (x,y): <PositionObjectn>}

我有一个函数需要返回给定位置周围特定范围内的 PositionObject 列表。现在我有这段代码对我来说工作得很好:

def getSurrounding(center_position, range, position_dictionnary):
    for x,y in position_dictionnary:
         if abs(center_position.x - x) + abs(center_position.y - y) < range:
             yield position_dictionnary[(x,y)]

但是当字典变得很大时,它就会变得太长,所以我问是否有一种方法可以直接循环字典的正确索引,或者我认为没有其他方法可以让它运行得更快。 (如果解决方案不是很好的实践证明,但速度更快,那就可以了)

最佳答案

您可以通过对 x 和 y 坐标进行双重排序来在亚线性时间内完成此操作。当然,这是假设点字典是相当静态的,因为添加或移动事物显然会产生(小)成本。

下面涉及使用多个排序容器,因此对 getSurrounding 的每个查询将调用 4 个二分搜索,这仍然是 O(log(N))。额外的好处是,这应该适用于位置的 float 值,但我还没有真正考虑过。

from sortedcollections import SortedDict, SortedList

pos_dict = {(0,0): 'a',
            (1,2): 'b',
            (1,3): 'c',
            (2,2): 'd',
            (2,6): 'e',
            (3,2): 'f',
            (4,4): 'g',
            (5,5): 'h'}

sd = SortedDict()

# put everything into a sorted dictionary
for x, y in pos_dict:
    temp = sd.get(x, SortedList())
    temp.add(y)
    sd[x] = temp

# we look for candidate x values in the sorted dictionary 
# and be clever with the Manhattan
# distance to find the y values

rng = 2
ctr = (2,2)
points_in_range = []

left_x = ctr[0] - rng
right_x = ctr[0] + rng

low_y = ctr[1] - rng
hi_y = ctr[1] + rng

x_vals = sd.keys()[sd.bisect(left_x) : sd.bisect(right_x)]

# get y values within the remaining Manhattan distance and construct tuples from (x, y)
for x in x_vals:
    temp = sd.get(x)
    low_y_lim = low_y + abs(x-ctr[0])
    hi_y_lim = hi_y - abs(x-ctr[0])
    y_vals = temp[temp.bisect(low_y_lim) : temp.bisect(hi_y_lim)]
    points_in_range.extend([(x, y) for y in y_vals])

print(points_in_range)

for p in points_in_range:
    print(f'{pos_dict.get(p)} is in range at location {p}')

产量:

[(1, 2), (1, 3), (2, 2), (3, 2)]
b is in range at location (1, 2)
c is in range at location (1, 3)
d is in range at location (2, 2)
f is in range at location (3, 2)

其他概念...

根据字典的大小和范围的值,您可能能够接近线性时间。如果 rng 的值很小,那么构造一组“在范围内”的点并将其与字典中的一组键相交非常容易,并且如果 rng 是“小”,则接近线性。

set_of_in_rng = {(x,y)      for x in range(ctr[0]-rng, ctr[0]+rng+1) 
                            for y in range(low_y+abs(x-2), hi_y-abs(x-2)+1)}

points_in_range = set_of_in_rng.intersection(set(pos_dict.keys()))

for p in points_in_range:
    print(f'{pos_dict.get(p)} is in range at location {p}')

产生相同的结果:

b is in range at location (1, 2)
f is in range at location (3, 2)
c is in range at location (1, 3)
d is in range at location (2, 2)

关于python - 字典Python的智能循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59843649/

相关文章:

python - 如何在 PyQt4/PySide 的 eventfilter 中的 QListWidget 之上进行绘制?

Swift - 如果键值字典中的值包含另一个键值对怎么办?

python - Visual C++ Redistributable 2015 已删除且无法重新安装

python - 如何增加预定义 x 范围的 x 轴上显示的厚度数量?

python - 在 Python 请求中将字典放入字典

java - Scala中如何处理Map的复杂操作

asp.net - GZIP 与 DEFLATE 压缩相比有何优势?

algorithm - 在仅限于不相交的正方形的情况下在网格上运行最佳洪水填充

python - 在 Cython 中优化字符串

python - 对 PyTorch 模型使用多处理 CPU 推理的最佳方法是什么?