2010-07-16 18 views
7

所以我有一個數組,包含幾個數字。隨着我的腳本運行,越來越多的數字被追加到這個數組。但是,我對所有的數字都不感興趣,只是想跟蹤最後5個數字。任何方式來跟蹤蟒蛇的最後5個數據點

目前,我只是將所有數字存儲在數組中。但是,這個數組變得非常大,並且充滿了不必要的信息。

我曾經想過如果一個函數當它向數組中添加一個元素,如果數組已經包含5個數字,也會刪除最後一個元素。

我也想過要創建一個新類來創建一個我想要的數據結構。但是,我只需要偶爾引用這個數組,並且只是腳本的一小部分。所以我認爲如果我創建一個全新的課程來做到這一點是過度的。

這樣做的最好方法是什麼?

回答

11

嘗試使用雙端隊列:。 http://docs.python.org/library/collections.html#deque-objects

「如果未指定或無,雙端隊列可能增長到任意長度的maxlen被否則,該雙端隊列爲界,指定的最大長度一旦有界長度雙端隊列已滿時,添加新項目時,相應數量的項目將從對端丟棄。有界長度deques提供的功能類似於Unix中的尾部篩選器,它們也可用於跟蹤事務和其他數據池,其中只有最最近的活動很有意思。「

+0

真棒這是完美的。謝謝。 – user 2010-07-16 00:42:03

+0

+1,但僅供參考,需要python 2.6或更高版本。 – 2010-07-16 01:31:04

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] 
+0

已經包含電池,先生;) – msw 2010-07-16 00:45:29

+0

@msw,唉,不在python 2.5.1這是我堅持... 有限的大小deque似乎只在python 2.6和更高。所以,如果你使用的是2.6+以上的有限長度的deques,否則你可以使用類似我的解決方案 – 2010-07-16 01:28:39

+0

+1 fair nuff,並且很好地說 – msw 2010-07-16 01:48:52

5

我使用Python的有限長度deque如果可用,的想法完全同意,如果沒有,邁克爾·安德森簡單的解決方案已經足夠。 (我把upvoted兩個)但是我只想提到環形緩衝區的第三個選項,當低內存佔用量和高執行速度很重要時,它通常用於這種任務。 (換句話說,在您可能不會使用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] 
    ^

等。

mylist = mylist[-5:] 

然後它會永遠只能是一個最大的5個值的長度

這裏:

+0

請注意,爲了獲得最後5個條目,您可以執行如下操作:def get_all(self):return self._buf [self._index:self._valid] + self._buf [:self._index] – 2010-07-16 05:25:57

+0

爲什麼計算n每次添加被稱爲? self._buf永遠不會改變長度,只需在'__init__'中添加'self._buflen = n'。要增加索引,更簡單的使用'self._index =(self._index + 1)%n'。我應該認爲,如果 PaulMcG 2010-07-16 10:55:41

+0

@Paul:我寫的代碼是一個奇怪的優化和效率混合;-)但這裏是我的推理:我在每次調用'add'時計算'n',因爲它被多次使用並將其存儲在本地變量中保存屬性查找。 '%'操作符往往很慢,但用'if'語句重置爲0會更快。你可能有一點關於設置'self._valid = self._index'。如果你知道你在填充之前不需要訪問緩衝區,'_valid'完全可以被省略。 – 2010-07-16 16:04:06

0

從你的描述,我只想擴展列表中的代碼之後添加以下語句類型是一個簡單的例子:

>>> 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] 
>>> 
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] 
+0

酷:-)這可能是一個更好的方式來做到這一點 - 當我寫我的時候,我正在考慮更多的從C(當然沒有類)的翻譯線。 +1 – 2010-07-16 16:13:24