2016-09-27 69 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: