Python:迭代一个集合,所以我们不会多次比较相同的对象?

Jes*_*eTG 3 python iteration comparison set

所以我正在写一个游戏.以下是碰撞检测的工作原理; 有一个不可见的网格,并且根据它们的位置在单元格中添加和删除对象(或者更确切地说,它们的引用).碰撞比较仅在同一单元格中的对象之间进行.

引用存储在set每个单元所拥有的Python 中.它必须是一套.当检测到碰撞时,它存储在Collision具有三个属性的对象中; 碰撞的两个物体和碰撞发生的时间.当考虑所有碰撞时,它们按时间排序,然后进行处理.

这是各个单元用于检查冲突的循环;

#grid.collisions is a list of recorded collisions, and self.objects is the set
#of objects currently in this cell.

for i in self.objects:
    for j in self.objects:
        if id(i) != id(j) and pygame.sprite.collide_rect(i, j):
            grid.collisions.append(Collision(i, j))
Run Code Online (Sandbox Code Playgroud)

问题是,这比较了两个相同的两个对象; 如果我们有一套{1, 2, 3, 4},我们会比较(1, 2) (2, 1).不仅如此,这些重复的比较被添加到总冲突列表中,从而打破了整个系统!

我知道我不能索引集合,这意味着我不能做像for j in range(i, len(self.objects))在哪里i,j都是整数. 如何解决此限制以确保同一组中的两个对象不进行两次比较? 我无法删除这些集合中的对象; 只有在对象离开网格单元格时才会删除它们.

由于每帧都会处理这些冲突,我宁愿避免创建新对象(真正的代码不像Collisions示例那样创建新的,我只是简化它以便于阅读).我可以删除重复的比较,但是将每次碰撞与其他碰撞进行比较会产生很多开销.

jdi*_*jdi 7

如果你的目标只是比较集合的所有独特组合,你可以使用 itertools.combinations

from itertools import combinations

for i, j in combinations(self.objects, 2):
    if pygame.sprite.collide_rect(i, j):
        grid.collisions.append(Collision(i, j))
Run Code Online (Sandbox Code Playgroud)

例:

aSet = set([1,2,3,4])
list(combinations(aSet, 2))
# [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
Run Code Online (Sandbox Code Playgroud)

combinations 与管理多个索引和临时列表相比,它生成了一个非常高效的生成器

  • `numpy`具有快速矩阵运算,但对于排列或组合没有什么特别之处.并且`itertools`是为速度而设计的.你可以把它作为一个规则:任何时候你想要更快地创造一些东西,想想是否有办法使用`itertools`. (2认同)