2016-09-27 74 views
0

假设我有一个包含运动对象实例的字典。每个运动物体都有一个位置,速度等。在程序的每个时间步更新中,我想检查两个活动物体(不是同一个物体,请注意)在参考系中占据相同的位置。如果他们这样做,这将模拟碰撞,涉及的两个对象将被销毁,并且他们的实例将从活动对象字典中移除。从字典中删除项目的应用

dict actives{ 'missile' : object_c(x1, y1, z1), 
       'target' : object_c(x2, y2, z2), 
       'clutter' : object_c(x3, y3, z3), 
       ...        } 

... 

for key1 in self.actives.keys(): 
    for key2 in self.actives.keys(): 
     if not key1 == key2: 
     # Get Inertial Positions and Distance 
     Pos21 = self.actives[key2].Pos - self.actives[key1].Pos 
     distance = math.sqrt(sum(Pos21**2)) 
     # If Distance <= Critical Distance 
     if distance <= 1.0e0 
      # Remove key1 and key2 from Actives 
      # -- This is where I need help -- 

我不能使用del:键(和对象)将来自活性被删除,但for循环条件未能认识到这一点,就会遇到一个KeyError异常。在访问循环条件的键时,我能做些什么来从活动中删除这些对象?

回答

1

我认为马克西米利安彼得斯有正确的基本我dea,但要删除的项目应保存在set而不是list中,以避免多次激活密钥的问题。为了进一步加速碰撞检测过程,我将比较循环改为使用itertools.combinations()生成器函数,以便仅测试唯一对象对。

我也不得不加脚手架相当数量,使其可能测试在上下文就像你可能有它运行的代码......

from itertools import combinations 
import math 

CRITICAL_DIST = 2.0e0 

class ObjectC(object): 
    def __init__(self, x, y, z): 
     self.posn = x, y, z 
    def __repr__(self): 
     return '{}({}, {}, {})'.format(self.__class__.__name__, *self.posn) 

class Game(object): 
    def remove_collisons(self): 
     to_remove = set() 
     for key1, key2 in combinations(self.actives, 2): 
      # Calculate distance. 
      deltas = (
       (self.actives[key2].posn[0] - self.actives[key1].posn[0])**2, 
       (self.actives[key2].posn[1] - self.actives[key1].posn[1])**2, 
       (self.actives[key2].posn[2] - self.actives[key1].posn[2])**2) 
      distance = math.sqrt(sum(deltas)) 
      # Check for collision. 
      if distance <= CRITICAL_DIST: 
       to_remove |= {key1, key2} # both objects should be removed 

     if to_remove: 
      print('removing: {!r}'.format(list(to_remove))) 
      self.actives = { 
       k: v for k, v in self.actives.items() if k not in to_remove} 

x1, y1, z1 = 0, 1, 2 
x2, y2, z2 = 1, 2, 3 
x3, y3, z3 = 2, 3, 1 

actives = {'missile' : ObjectC(x1, y1, z1), 
      'target' : ObjectC(x2, y2, z2), 
      'clutter' : ObjectC(x3, y3, z3), 
      } # ... 

game = Game() 
game.actives = actives 
print('before: {}'.format(game.actives)) 
game.remove_collisons() 
print('after: {}'.format(game.actives)) 

输出:

before: {'clutter': ObjectC(2, 3, 1), 'target': ObjectC(1, 2, 3), 'missile': ObjectC(0, 1, 2)} 
removing: ['target', 'missile'] 
after: {'clutter': ObjectC(2, 3, 1)} 
1

简单的解决方案,添加要删除到一个列表,然后将其删除键通的所有元素循环后:

dict actives{ 'missile' : object_c(x1, y1, z1), 
      'target' : object_c(x2, y2, z2), 
      'clutter' : object_c(x3, y3, z3), 
      ...        } 
to_be_removed = list() 

...

for key1 in self.actives.keys(): 
    for key2 in self.actives.keys(): 
     if not key1 == key2: 
     # Get Inertial Positions and Distance 
     Pos21 = self.actives[key2].Pos - self.actives[key1].Pos 
     distance = math.sqrt(sum(Pos21**2)) 
     # If Distance <= Critical Distance 
     if distance <= 1.0e0 
      # Remove key1 and key2 from Actives 
      # -- This is where I need help -- 


      to_be_removed.append(key1) 
      to_be_removed.append(key2) 

for remove_me in to_be_removed: 
    self.actives.pop(remove_me, None) 
+0

那似乎是正确的,但是在正确的条件下,如果to_be_removed列表与其他两个对象占据相同的位置(即,key1和key2之间的距离为0.5,key1和key3之间的距离为0.5),则'to_be_removed'列表可能具有多个'key1'是0.75)。在列表中具有相同密钥的副本也会导致'pop'上的KeyError。但是,也许我们可以记录'to_be_removed'列表,并在从字典中弹出之前清除它(消除重复的键)。 –

+0

@ S.Gamgee:如果您指定'default'值(在这种情况下为'None'),如果您从列表中删除密钥,则不会出现错误。 https://docs.python.org/3.5/library/stdtypes.html –

1

当你循环,你可以仔细检查钥匙是否仍然存在:

for key1 in self.actives.keys(): 

    if key1 not in self.actives: 
     continue 

    for key2 in self.actives.keys(): 

     if key2 not in self.actives: 
      continue 

     # okay, both keys are still here. go do stuff 
     if not key1 == key2: