在Python中如何追踪最后5个数据点?
我有一个数组,里面存着几个数字。随着我的脚本运行,越来越多的数字被添加到这个数组里。不过,我其实只想关注最后的5个数字。
现在,我只是把所有的数字都存进这个数组里。但是,这个数组变得非常大,里面充满了不必要的信息。
我想过做一个函数,每当往数组里添加一个新元素时,如果数组里已经有5个数字,就把最后一个数字删掉。
我也考虑过创建一个新的类,来做一个数据结构,满足我的需求。不过,我只偶尔需要用到这个数组,而且它只是脚本中的一小部分。所以我觉得创建一个全新的类来实现这个功能有点过于复杂了。
那么,最好的解决办法是什么呢?
5 个回答
这个类可以非常简单:
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]
我完全同意使用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]
^
以此类推。
可以试试使用一个叫做deque的东西:
http://docs.python.org/library/collections.html#deque-objects
“如果没有指定最大长度或者设置为None,deque的长度可以随意增长。否则,deque的长度会被限制在指定的最大值。一旦这个有限长度的deque满了,当你添加新的项目时,它会从另一端丢掉相应数量的项目。有限长度的deque功能类似于Unix中的尾部过滤器。它们也很适合用来跟踪交易和其他数据池,特别是当你只关心最新的活动时。”