2015-11-01 44 views
0

是否存在對任意類的對象列表中的每個元素(或更準確地說是元素的子集)執行簡單遞減操作的pythonic /高效方法?在對象列表中矢量化遞減操作

我可能有一個大對象(〜10K)對象列表,每個對象都是基於倒計時「更新時間」(TTU)值而定期更新的。

簡單的方式來處理,這將是遞減的,如下每個元素此值:

def BatesNumber(start = 0): 
    n = start 
    while True: 
     yield n 
     n += 1 

class foo: 
    index = BatesNumber() 

    def __init__(self, ttu): 
     self.id = next(foo.index) 
     self.time = ttu 
     self.ttu = ttu 

    def __repr__(self): 
     return "#{}:{}/{}".format(self.id, self.ttu, self.time) 

    def Decrement(self): 
     self.ttu -= 1 

    def Reset(self): 
     print("Reset {} to {}".format(self.id, self.time)) 
     self.ttu = self.time 

    def IsReadyForUpdate(self): 
     if self.ttu == 0: 
      return True 
     else: 
      return False 



bar = [foo(i) for i in range(10, 20, 2)] 

for n in range(50): 
    for p in bar: 
     if p.IsReadyForUpdate(): 
      print("{} {}".format(n, p)) 
      p.Reset() 
     else: 
      p.Decrement() 

所以我想我是後是「向量化」的減量操作的一些Python的方式 - 即減量以適當優雅的方式列表中的所有元素;並且理想地返回那些需要更新/重置的元素。

我可以(雖然看起來有點不必要的可怕)產生一個按照TTU值排序的列表,並且具有相對於它們的鄰居的所有TTU值。這樣我每循環只需要一次遞減,但是當我重置計數器時,我有重建列表的痛苦。我想這對TTU值相當高的非常長的名單會更好。

我認爲最好的/ Pythonic的方法來檢查哪些元素準備好更新正在使用列表理解。

有什麼建議嗎?

回答

1

也許你可以使用heapq模塊,用優先級隊列替換你的平面列表。優先級將是當前時間,加上對象的ttu。當前時間與頂層元素的優先級相匹配時,您可以將其彈出,執行更新操作,然後以新的優先級將其重新插入隊列中。

的代碼會是這個樣子:

import heapq 

items = [foo(i) for i in range(10,20)] 

queue = [(f.ttu, f.id, f) for f in items] 
heapq.heapify(queue) 

for t in range(50): 
    while t >= queue[0][0]: 
     _, _, f = heapq.heappop(queue) 
     # update f here 
     heapq.heappush(queue, (t + f.ttu, f.id, f)) 

我使用對象的id屬性作爲決勝當兩個對象需要在同一時間進行更新。如果您願意,可以通過在對象中實現__lt__運算符來使優先級隊列實現更容易,從而使它們可以直接進行比較。如果您讓它們跟蹤自己的更新時間,則隊列可以直接包含對象(如items列表)而不是元組,以便按照優先級排序。

喜歡的東西:

class foo: 
    index = BatesNumber() 

    def __init__(self, ttu): 
     self.id = next(index) 
     self.next_update = ttu 
     self.ttu = ttu 

    def __lt__(self, other): 
     return (self.next_update, self.id) < (other.next_update, other.id) 

    # ideally you'd also write __eq__, __gt__, etc. methods, but heapq only needs __lt__ 

    def update(self): 
     self.next_update += self.ttu 
     # maybe do other update stuff here? 

順便說一句,你BatesNumber類是itertools.count基本相同。

0

我認爲你的代碼已經很好;也許你可以添加一個名爲類似「打」一個單一的方法進行兩件事:

  • 檢查,如果對象是準備更新,並在這種情況下,處理更新,
  • 或在其他情況下遞減;

它會讓你的循環更清潔簡單。對你的問題的「向量化」部分沒有多大幫助,但是在「面向對象」的編程方式中它會更深入。

對於「向量化」部分;在整個過程中你的名單會有很大變化嗎?一個想法可能是:有一個單獨的Numpy數組,其中包含要減少的值並使該表與索引匹配。當然,如果你在計算過程中必須抑制實例,那麼這將不是很方便,但如果不是這樣的話,它可能是要走的路。

+0

列表本身不會改變:它會保持相同的大小,但是當TTU耗盡在它單個元素將被更新,然後TTU將被重置。目前(雖然我對這個問題的思考還在開發中)我懷疑,列表中的每個元素都將更新平均約每5-10「蜱」,所以每次勾選對象的10%-20%將更新。 (也許我應該在我的職務,我希望它循環提到說每10毫秒或者如果可能的話,也許1毫秒,因此需要一個高效的更新)。 – TimGJ