在Python中如何追踪最后5个数据点?

11 投票
5 回答
2900 浏览
提问于 2025-04-16 01:22

我有一个数组,里面存着几个数字。随着我的脚本运行,越来越多的数字被添加到这个数组里。不过,我其实只想关注最后的5个数字。

现在,我只是把所有的数字都存进这个数组里。但是,这个数组变得非常大,里面充满了不必要的信息。

我想过做一个函数,每当往数组里添加一个新元素时,如果数组里已经有5个数字,就把最后一个数字删掉。

我也考虑过创建一个新的类,来做一个数据结构,满足我的需求。不过,我只偶尔需要用到这个数组,而且它只是脚本中的一小部分。所以我觉得创建一个全新的类来实现这个功能有点过于复杂了。

那么,最好的解决办法是什么呢?

5 个回答

4

这个类可以非常简单:

class ListOfFive:
  def __init__(self):
    self.data = []
  def add(self,val):
    if len(self.data)==5:
      self.data=self.data[1:]+[val]
    else:
      self.data+=[val]

l = ListOfFive()
for i in range(1,10):
  l.add(i)
  print l.data

输出结果是:

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]
[3, 4, 5, 6, 7]
[4, 5, 6, 7, 8]
[5, 6, 7, 8, 9]
7

我完全同意使用Python的有限长度的deque,如果可以的话。如果不行,Michael Anderson的简单解决方案也很不错。(我给了两个赞)不过我想提一下第三种选择,就是环形缓冲区。这种结构在内存占用小和执行速度快的时候特别有用。(换句话说,就是在你可能不会用Python的情况下 :-p)比如,Linux内核就用这种结构来存储在启动过程中生成的日志信息,直到系统日志记录器启动。

在Python中的实现可能是这样的:

class RingBuffer(object):
    def __init__(self, n):
        self._buf = [None] * n
        self._index = 0
        self._valid = 0
    def add(self, obj):
        n = len(self._buf)
        self._buf[self._index] = obj
        self._index += 1
        if self._index == n
            self._index = 0
        if self._valid < n:
            self._valid += 1
    def __len__(self):
        return self._valid
    # could include other methods for accessing or modifying the contents

基本上,它的做法是预先分配一个指定长度的数组(在Python中是一个列表),并用一些虚拟值填充它。这个缓冲区还包含一个“索引”,指向列表中下一个应该填入值的位置。每次添加一个值时,就把它存储在那个位置,并把索引加一。当索引达到数组的长度时,它会重置为零。这里有个例子(我用0代替None作为虚拟值,因为这样输入更快):

[0,0,0,0,0]
 ^
# add 1
[1,0,0,0,0]
   ^
# add 2
[1,2,0,0,0]
     ^
# add 3
[1,2,3,0,0]
       ^
# add 4
[1,2,3,4,0]
         ^
# add 5
[1,2,3,4,5]
 ^
# add 6
[6,2,3,4,5]
   ^
# add 7
[6,7,3,4,5]
     ^

以此类推。

15

可以试试使用一个叫做deque的东西:

http://docs.python.org/library/collections.html#deque-objects

“如果没有指定最大长度或者设置为None,deque的长度可以随意增长。否则,deque的长度会被限制在指定的最大值。一旦这个有限长度的deque满了,当你添加新的项目时,它会从另一端丢掉相应数量的项目。有限长度的deque功能类似于Unix中的尾部过滤器。它们也很适合用来跟踪交易和其他数据池,特别是当你只关心最新的活动时。”

撰写回答