所以我有一个包含多个数字的数组。当我的脚本运行时,会有越来越多的数字附加到此数组中。但是,我对所有数字都不感兴趣,只是想跟踪最后5个数字。
目前,我只是将所有数字存储在数组中。但是,这个数组变得非常大,并且充满了不必要的信息。
我已经考虑过创建一个函数,当它向数组添加元素时,如果数组已包含5个数字,也会删除最后一个元素。
我还想过创建一个新类来创建一个能够满足我想要的数据结构。但是,我只需要偶尔引用这个数组,这只是脚本的一小部分。所以我认为如果我创建一个全新的类来做这件事就太过分了。
这样做的最佳方式是什么?
答案 0 :(得分:11)
尝试使用双端队列: http://docs.python.org/library/collections.html#deque-objects
“如果未指定maxlen或者为None,则deques可能会增长到任意长度。否则,deque将限制为指定的最大长度。一旦有限长度deque已满,添加新项目时,相应的数字从相反的一端丢弃项目。有界长度deques提供类似于Unix中的尾部过滤器的功能。它们也可用于跟踪只有最近活动感兴趣的事务和其他数据池。“
答案 1 :(得分:5)
我完全赞同使用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]
^
等等。
答案 2 :(得分: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]
答案 3 :(得分:2)
在ActiveState Recipes中可以找到另一个整洁的环缓冲区实现 - 您的环缓冲区对象在最初填充时作为RingBuffer的实例开始,然后您的实例更改其类到RingBufferFull,一个优化的完整实现。它总是让我微笑。
class RingBuffer:
def __init__(self,size_max):
self.max = size_max
self.data = []
def append(self,x):
"""append an element at the end of the buffer"""
self.data.append(x)
if len(self.data) == self.max:
self.cur=0
self.__class__ = RingBufferFull
def get(self):
""" return a list of elements from the oldest to the newest"""
return self.data
class RingBufferFull:
def __init__(self,n):
raise "you should use RingBuffer"
def append(self,x):
self.data[self.cur]=x
self.cur=(self.cur+1) % self.max
def get(self):
return self.data[self.cur:]+self.data[:self.cur]
答案 4 :(得分:0)
根据您的描述,我会在扩展您的列表的代码之后添加以下类型的语句:
mylist = mylist[-5:]
它的长度最多只有5个值
这是一个简单的例子:
>>> mylist = []
>>> i = 1
>>> while i<6:
print ("\n Pre addition: %r" % mylist)
mylist += range(i)
print (" Addition: %r" % mylist)
mylist = mylist[-5:]
print (" Chopped: %r" % mylist)
i += 1
Pre addition: []
Addition: [0]
Chopped: [0]
Pre addition: [0]
Addition: [0, 0, 1]
Chopped: [0, 0, 1]
Pre addition: [0, 0, 1]
Addition: [0, 0, 1, 0, 1, 2]
Chopped: [0, 1, 0, 1, 2]
Pre addition: [0, 1, 0, 1, 2]
Addition: [0, 1, 0, 1, 2, 0, 1, 2, 3]
Chopped: [2, 0, 1, 2, 3]
Pre addition: [2, 0, 1, 2, 3]
Addition: [2, 0, 1, 2, 3, 0, 1, 2, 3, 4]
Chopped: [0, 1, 2, 3, 4]
>>>