在对象列表上矢量化减量操作

时间:2015-11-01 16:06:28

标签: python list

是否有一种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()

所以我猜我所追求的是一种“向量化”递减操作的Pythonic方式 - 即以适当优雅的方式递减列表中的所有元素;理想情况下,返回那些需要更新/重置的元素。

我可以(尽管看起来有点不必要)生成一个按TTU值排序的列表,并且具有相对于其邻居的所有TTU值。这样我每个周期只需要减少一次,但是当我重置计数器时,我很难重建列表。我想这对于一个具有相当高的TTU值的很长的列表会更好。

我假设使用列表理解来检查哪些元素已准备好进行更新的最佳/ Pythonic方法。

有什么建议吗?

2 个答案:

答案 0 :(得分: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相同。

答案 1 :(得分:0)

我认为你的代码已经很好了;也许你可以添加一个名为&#34; beat&#34;执行这两件事:

  • 检查对象是否准备好更新,并在这种情况下处理更新,
  • 或在另一种情况下减少;

它会使你的循环更清洁,更简单。它对#34;矢量化&#34;它不会有多大帮助。你问题的一部分,但它会更深入地面向对象&#34;编程方式。

对于&#34;矢量化&#34;部分;你的清单会在整个过程中发生很大变化吗?一个想法可能是:有一个单独的Numpy数组,其中包含要递减的值,并使表与索引的列表匹配。当然,如果你必须在计算过程中抑制实例,那将是不太方便的,但如果不是这样,那么可能就是这样。