2010-08-02 31 views
1

Je veux construire une structure de données pour stocker tampon Undo limité, prenez magasin 6 données dict par exemple avec ci-dessous pseudocode:Comment créer un stockage d'annulation avec limite?

rawdict1 = {1} 
buffer = [{1}] 

rawdict1 = {2} 
buffer = [{2}{1}]  # {1} stored on the postion 

rawdict1 = {3} 
buffer = [{3}{2}{1}]  
... 
rawdict1 = {5} 
buffer = [{5}{4}{3}{2}{1}]  # max length limited to 5 

rawdict1 = {6} 
buffer = [{6}{5}{4}{3}{2}]  # {1} has been deleted because exceed the limit 

when I want to restore the rawdict1 later, I can use something looks like: 

rawdict1 = buffer[5]     # restore the 5th dict. 

Ma question est, peut déjà le type de données buildin ou le type de bibliothèque standard peut être utilisé pour une telle un but?

Et est-il possible qu'une telle structure peut stocker des multi-types dans une instance de structure, par exemple, si je veux stocker dict et la classe auto-définie en une seule fois?

Merci!

RBP,

KC

Répondre

2

peut-être utiliser quelque chose comme ceci:

import collections 

class UndoBuffer(object): 
    def __init__(self,value,max_length=5): 
     self.max_length=max_length 
     self._buffer=collections.deque([value],max_length) 
    @property 
    def data(self): 
     return self._buffer[-1] 
    @data.setter 
    def data(self,value): 
     self._buffer.append(value) 
    def restore(self,index): 
     self.data=self._buffer[index] 

Faire un objet UndoBuffer

rawdict=UndoBuffer('{1}')  

Réglage de l'data attribut stocke automatiquement la valeur _buffer:

print(rawdict._buffer) 
# deque(['{1}'], maxlen=5) 
print(rawdict.data) 
# {1} 

Modification de la valeur de rawdict.data ajoute le v aleur à rawdict._buffer:

rawdict.data = '{2}' 
print(rawdict._buffer) 
# deque(['{1}', '{2}'], maxlen=5) 

Buf si vous accédez rawdict.data vous obtenez seulement la valeur la plus récente:

print(rawdict.data) 
# {2} 

Modifier la valeur d'un peu plus de temps. « {1} » est perdu lorsque la mémoire tampon est rempli à sa longueur maximale:

rawdict.data = '{3}' 
rawdict.data = '{4}' 
rawdict.data = '{5}' 
print(rawdict._buffer) 
# deque(['{1}', '{2}', '{3}', '{4}', '{5}'], maxlen=5) 
rawdict.data = '{6}' 
print(rawdict._buffer) 
# deque(['{2}', '{3}', '{4}', '{5}', '{6}'], maxlen=5) 

Restauration de la valeur de rawdict._buffer:

rawdict.restore(0) # set rawdict.data to rawdict._buffer[0] 
print(rawdict.data) 
# {2} 
print(rawdict._buffer) 
# deque(['{3}', '{4}', '{5}', '{6}', '{2}'], maxlen=5) 
0

Rockford Lhotka's CSLA.NET framework contient une architecture d'annulation. Peut-être que vous pourriez l'étudier et comprendre ce qu'il a fait, ou même l'utiliser hors de la boîte.

+0

Merci pour vos informations, Robert –

+0

mais un peu peut grand pour moi pour ma solution rapide. J'ai juste besoin d'un stockage peut stocker 5 copies des données brutes et assigner l'index pour eux. –

1

Vous ne pouvez pas le faire sur un barename (comme rawdict1) parce que vous n'avez aucun moyen d'intercepter des affectations à un nom de barre et de les faire parfois "sur le côté", par exemple en sauvegardant la valeur précédente. Il est facile de le faire sur un nom décoré, par exemple:

undoable.rawdict1 = {1} 

et similaires, en faisant undoable une instance d'une classe avec une __setitem__ appropriée qui ajoute la valeur précédente (le cas échéant) à une liste, et fait apparaître le 0ème élément si la liste devient trop longue. Mais cela ne suffira pas pour autres actions "annulables" en dehors de l'affectation, tels que undoable.rawdict1.update(whatever) - vous êtes sûr que vous n'avez pas besoin de cela?

+0

Je pense que vous avez fait deux étapes au-delà de ce dont le PO avait besoin ici. :-) Pour ma part, je me souviendrai de cette réponse quand un décorateur de classe "annulable" pourrait être utile! :-) – jsbueno

+0

merci Alex, content de vous voir répondre à nouveau. Peut-être pas une classe conteneur avec une action d'annulation intégrée ici, je veux un conteneur comme une bride pour le flux de données avec capacité d'annulation: il peut ressembler à ceci: data_consumers <=> undo_container <=> data_source *** data_consumers peut changer la source de données si je opéré sur la data_source directement donné aucun changement pour le restaurer, alors j'ai besoin d'un tampon et annuler l'opportunité ici. et le rawdata1 est les données de l'externe, peut-être que je dois faire un deepcopy puis les pousser dans la classe d'annulation? –

+0

@Registered, si vous pouvez faire le push en tant qu'action explicite à n'importe quel point significatif de votre choix, au lieu de l'avoir fait implicitement par des affectations à un nom de barre annulable, votre vie sera définitivement plus simple ;-). –

1

Vous pouvez rapidement sous-classer la liste pour n'autoriser qu'un stockage limité.Les listes Python ne doivent pas forcément être d'un certain type, comme les listes génériques en C#

class LimitedStack(list): 
def __init__(self,limit=6): 
    list.__init__(self) 
    self.limit = limit 

def append(self,obj): 
    if len(self) == self.limit: 
     list.pop(self,0) 
    list.append(self,obj) 
Ils vont stocker tout objet que vous leur ajoutez.

1

Le module collections, à partir de python 2.6, contient la collection "deque". Il se comporte comme vous avez besoin:

>>> import collections 
>>> buffer = collections.deque([],6) 
>>> buffer.extend(range(6)) 
>>> buffer 
deque([0, 1, 2, 3, 4, 5], maxlen=6) 
>>> buffer.append(6) 
>>> buffer 
deque([1, 2, 3, 4, 5, 6], maxlen=6) 
>>> buffer[-1] 
6