2015-11-01 41 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