Имеется только один словарь, сопоставляющий ключ с списком (revision_number, actual_value) кортежей. Текущее значение the_dict[akey][-1][1]
. Откат просто включает извлечение соответствующих записей из конца каждого списка.
Обновление: примеры отката
key1 -> [(10, 'v1-10'), (20, 'v1-20')]
Сценарий 1: текущая версия 30, откат до 25: ничего не происходит
Сценарий 2: текущие 30, назад к 15: всплыть последняя запись
Сценарий 3: текущий 30, назад к 5: вывести обе записи
Обновление 2: более быстрый откат (с компромиссами)
Я думаю, что ваше беспокойство по поводу высовывания каждого списка лучше выражается как «необходимо изучить каждый список, чтобы выяснить, нужно ли ему выскочить». Благодаря более изящной структуре данных (больше памяти, больше времени для поддержки модных битов в операциях добавления и обновления) вы можете сократить время отката.
Добавьте массив (проиндексированный по номеру ревизии), значения которого являются списками значений словаря, которые были изменены в этой ревизии.
# Original rollback code:
for rlist in the_dict.itervalues():
if not rlist: continue
while rlist[-1][0] > target_revno:
rlist.pop()
# New rollback code
for revno in xrange(current_revno, target_revno, -1):
for rlist in delta_index[revno]:
assert rlist[-1][0] == revno
del rlist[-1] # faster than rlist.pop()
del delta_index[target_revno+1:]
Обновление 3: полный код для более необычного метода
import collections
class RevDict(collections.MutableMapping):
def __init__(self):
self.current_revno = 0
self.dict = {}
self.delta_index = [[]]
def __setitem__(self, key, value):
if key in self.dict:
rlist = self.dict[key]
last_revno = rlist[-1][0]
rtup = (self.current_revno, value)
if last_revno == self.current_revno:
rlist[-1] = rtup
# delta_index already has an entry for this rlist
else:
rlist.append(rtup)
self.delta_index[self.current_revno].append(rlist)
else:
rlist = [(self.current_revno, value)]
self.dict[key] = rlist
self.delta_index[self.current_revno].append(rlist)
def __getitem__(self, key):
if not key in self.dict:
raise KeyError(key)
return self.dict[key][-1][1]
def new_revision(self):
self.current_revno += 1
self.delta_index.append([])
def roll_back(self, target_revno):
assert 0 <= target_revno < self.current_revno
for revno in xrange(self.current_revno, target_revno, -1):
for rlist in self.delta_index[revno]:
assert rlist[-1][0] == revno
del rlist[-1]
del self.delta_index[target_revno+1:]
self.current_revno = target_revno
def __delitem__(self, key):
raise TypeError("RevDict doesn't do del")
def keys(self):
return self.dict.keys()
def __contains__(self, key):
return key in self.dict
def iteritems(self):
for key, rlist in self.dict.iteritems():
yield key, rlist[-1][1]
def __len__(self):
return len(self.dict)
def __iter__(self):
return self.dict.iterkeys()