简体   繁体   English

向量化对象清单上的减量运算

[英]Vectorising a decrement operation on a list of objects

Is there a pythonic/efficient way to carry out a simple decrement operation on each element (or more accurately a subset of the elements) in a list of objects of an arbitrary class? 是否有Python高效的方法来对任意类的对象列表中的每个元素(或更准确地说是元素的子集)执行简单的递减运算?

I potentially have a large-ish (~ 10K) list of objects, each of which is updated periodically on the basis of a countdown "time to update" (TTU) value. 我可能有一个很大的对象列表(〜10K),每个对象列表都会根据倒计时“更新时间”(TTU)值进行定期更新。

The simple way to handle this would be to decrement this value in each element as below: 解决此问题的简单方法是,按如下所示递减每个元素中的该值:

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()

So I guess what I am after is some Pythonic way of "vectorising" the decrement operation - ie decrement all the elements in the list in a suitably elegant way; 因此,我想我所追求的是某种Python方式将减量操作“矢量化”,即以适当的优雅方式减量列表中的所有元素; and, ideally, returning those elements which require update/reset. 理想情况下,返回需要更新/重置的那些元素。

I could (although it seems a bit unnecessarily horrible) produce a list which is ordered on the TTU value, and have all the TTU values relative to their neighbour. 我可以(尽管看起来有些不必要地可怕)产生一个按TTU值排序的列表,并具有相对于其邻居的所有TTU值。 That way I would only require one decrement per cycle, but then when I reset the counter I have the pain of rebuilding the list. 这样,我每个周期只需要递减1,但是当我重置计数器时,我便会重新构建列表。 I suppose that this would be better for a very long list with quite high TTU values. 我认为这对于具有相当高的TTU值的较长列表会更好。

I presume the best/Pythonic way to check which of the elements is ready for update is using a list comprehension. 我假设使用列表推导来检查哪个元素准备更新的最佳/ Python方式。

Any advice? 有什么建议吗?

Perhaps you could replace your flat list with a priority queue using the heapq module. 也许您可以使用heapq模块将优先列表替换为优先队列。 The priorities would be the current time, plus the object's ttu . 优先级将是当前时间,加上对象的ttu When the current time matched the top element's priority, you'd pop it off, do whatever your updating was, and then push it back into the queue with a new priority. 当当前时间与最高元素的优先级匹配时,您将其弹出,进行任何更新,然后将其以新的优先级推回到队列中。

The code would look something like this: 代码看起来像这样:

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))

I'm using the object's id attribute as a tie breaker when two objects need to be updated at the same time. 当两个对象需要同时更新时,我将对象的id属性用作平局。 If you wanted to, you could make the priority queue implementation easier by implementing a __lt__ operator in the objects to allow them to be compared directly. 如果愿意,可以通过在对象中实现__lt__运算符来使它们直接进行比较,从而使优先级队列的实现更加容易。 If you made them track their own update times, the queue could just contain the objects directly (like the items list) rather than tuples to make them sort in order of priority. 如果让它们跟踪自己的更新时间,则队列可以直接包含对象(如items列表),而不是元组以使它们按优先级排序。

Something like: 就像是:

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?

By the way, your BatesNumber class is essentially identical to itertools.count . 顺便说一下,您的BatesNumber类与itertools.count本质上是相同的。

I think your code is already good; 我认为您的代码已经不错了; maybe you could add a single method called something like "beat" for performing both things: 也许您可以添加一个称为“ beat”的方法来执行这两种操作:

  • checking if the object is ready to update and in that case handle the update, 检查对象是否准备好更新,并且在这种情况下,请处理更新,
  • or decrement in the other case; 或者在其他情况下递减;

it would make your loop a little cleaner and simpler. 它会使您的循环更干净,更简单。 It won't help much for the "vectorization" part of your question but it would go deeper in the "object oriented" way of programming. 对于您问题的“向量化”部分没有太大帮助,但在“面向对象”的编程方式中会更深入。

For the "vectorization" part; 对于“矢量化”部分; will your list change much during the whole process? 您的清单在整个过程中会发生很大变化吗? One idea could be: have a separate Numpy array containing the values to be decremented and have the table matching your list by the index. 一个想法可能是:有一个单独的Numpy数组,其中包含要减少的值,并使表按索引与您的列表匹配。 Of course it will not be very convenient if you have to suppress instances during the computation but if it isn't the case, it may be the way to go. 当然,如果在计算过程中必须抑制实例,这将不是很方便,但如果不是这种情况,则可能是可行的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM